Kapt: Support correctErrorTypes in suspend functions (KT-27711)

This commit is contained in:
Yan Zhulanow
2018-11-08 16:23:14 +09:00
parent 4c5e982f3e
commit 6a8a8b794d
4 changed files with 49 additions and 11 deletions
@@ -122,6 +122,8 @@ val INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION = object : CallableDescriptor.UserDa
@JvmField @JvmField
val INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {} val INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
val CONTINUATION_PARAMETER_NAME = Name.identifier("continuation")
// Resolved calls to suspension function contain descriptors as they visible within coroutines: // Resolved calls to suspension function contain descriptors as they visible within coroutines:
// E.g. `fun <V> await(f: CompletableFuture<V>): V` instead of `fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>): Unit` // E.g. `fun <V> await(f: CompletableFuture<V>): V` instead of `fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>): Unit`
// See `createJvmSuspendFunctionView` and it's usages for clarification // See `createJvmSuspendFunctionView` and it's usages for clarification
@@ -258,7 +260,7 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
original = null, original = null,
index = function.valueParameters.size, index = function.valueParameters.size,
annotations = Annotations.EMPTY, annotations = Annotations.EMPTY,
name = Name.identifier("continuation"), name = CONTINUATION_PARAMETER_NAME,
// Add j.l.Object to invoke(), because that is the type of parameters we have in FunctionN+1 // Add j.l.Object to invoke(), because that is the type of parameters we have in FunctionN+1
outType = if (function.containingDeclaration.safeAs<ClassDescriptor>()?.defaultType?.isBuiltinFunctionalType == true) outType = if (function.containingDeclaration.safeAs<ClassDescriptor>()?.defaultType?.isBuiltinFunctionalType == true)
function.builtIns.nullableAnyType function.builtIns.nullableAnyType
@@ -25,6 +25,9 @@ import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.tree.TreeScanner import com.sun.tools.javac.tree.TreeScanner
import kotlinx.kapt.KaptIgnored import kotlinx.kapt.KaptIgnored
import org.jetbrains.kotlin.base.kapt3.KaptFlag import org.jetbrains.kotlin.base.kapt3.KaptFlag
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_PARAMETER_NAME
import org.jetbrains.kotlin.codegen.needsExperimentalCoroutinesWrapper
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -46,6 +49,7 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
@@ -743,7 +747,8 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
private fun extractMethodSignatureTypes( private fun extractMethodSignatureTypes(
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
exceptionTypes: JavacList<JCExpression>, exceptionTypes: JavacList<JCExpression>,
jcReturnType: JCExpression?, method: MethodNode, jcReturnType: JCExpression?,
method: MethodNode,
parameters: JavacList<JCVariableDecl>, parameters: JavacList<JCVariableDecl>,
valueParametersFromDescriptor: List<ValueParameterDescriptor> valueParametersFromDescriptor: List<ValueParameterDescriptor>
): Pair<SignatureParser.MethodGenericSignature, JCExpression?> { ): Pair<SignatureParser.MethodGenericSignature, JCExpression?> {
@@ -760,12 +765,23 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
}, },
ifNonError = { lazyType() }) ifNonError = { lazyType() })
} else if (descriptor is FunctionDescriptor && valueParametersFromDescriptor.size == parameters.size) { } else if (descriptor is FunctionDescriptor && valueParametersFromDescriptor.size == parameters.size) {
getNonErrorType(valueParametersFromDescriptor[index].type, METHOD_PARAMETER_TYPE, val parameterDescriptor = valueParametersFromDescriptor[index]
ktTypeProvider = { val sourceElement = kaptContext.origins[method]?.element as? KtFunction
val sourceElement = kaptContext.origins[method]?.element as? KtFunction
sourceElement?.valueParameters?.getOrNull(index)?.typeReference getNonErrorType(
}, parameterDescriptor.type, METHOD_PARAMETER_TYPE,
ifNonError = { lazyType() }) ktTypeProvider = {
if (sourceElement == null) return@getNonErrorType null
if (sourceElement.hasDeclaredReturnType() && isContinuationParameter(parameterDescriptor)) {
val continuationTypeFqName = getContinuationTypeFqName(descriptor)
val functionReturnType = sourceElement.typeReference!!.text
KtPsiFactory(kaptContext.project).createType("$continuationTypeFqName<$functionReturnType>")
} else {
sourceElement.valueParameters.getOrNull(index)?.typeReference
}
},
ifNonError = { lazyType() })
} else { } else {
lazyType() lazyType()
} }
@@ -788,7 +804,26 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
return Pair(genericSignature, returnType) return Pair(genericSignature, returnType)
} }
private inline fun <T : JCExpression?> getNonErrorType( private fun isContinuationParameter(descriptor: ValueParameterDescriptor): Boolean {
val containingCallable = descriptor.containingDeclaration
return containingCallable.valueParameters.lastOrNull() == descriptor
&& descriptor.name == CONTINUATION_PARAMETER_NAME
&& descriptor.source == SourceElement.NO_SOURCE
&& descriptor.type.constructor.declarationDescriptor?.fqNameSafe == getContinuationTypeFqName(containingCallable)
}
private fun getContinuationTypeFqName(descriptor: CallableDescriptor): FqName {
val areCoroutinesReleased = !descriptor.needsExperimentalCoroutinesWrapper()
&& kaptContext.generationState.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
return when (areCoroutinesReleased) {
true -> DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME_RELEASE
false -> DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME_EXPERIMENTAL
}
}
private fun <T : JCExpression?> getNonErrorType(
type: KotlinType?, type: KotlinType?,
kind: ErrorTypeCorrector.TypeKind, kind: ErrorTypeCorrector.TypeKind,
ktTypeProvider: () -> KtTypeReference?, ktTypeProvider: () -> KtTypeReference?,
@@ -1,4 +1,5 @@
// CORRECT_ERROR_TYPES // CORRECT_ERROR_TYPES
// NO_VALIDATION
// WITH_RUNTIME // WITH_RUNTIME
@file:Suppress("UNRESOLVED_REFERENCE") @file:Suppress("UNRESOLVED_REFERENCE")
@@ -5,13 +5,13 @@ public final class Foo {
@org.jetbrains.annotations.Nullable() @org.jetbrains.annotations.Nullable()
public final java.lang.Object a(@org.jetbrains.annotations.NotNull() public final java.lang.Object a(@org.jetbrains.annotations.NotNull()
kotlin.coroutines.Continuation<? super error.NonExistentClass> p0) { kotlin.coroutines.Continuation<ABC> p0) {
return null; return null;
} }
@org.jetbrains.annotations.Nullable() @org.jetbrains.annotations.Nullable()
public final java.lang.Object b(@org.jetbrains.annotations.NotNull() public final java.lang.Object b(@org.jetbrains.annotations.NotNull()
kotlin.coroutines.Continuation<? super kotlin.Result<? extends error.NonExistentClass>> p0) { kotlin.coroutines.Continuation<Result<ABC>> p0) {
return null; return null;
} }