Implement callable references to suspend functions

In FE they have type KSuspendFunctionN
In BE they are treated like normal callable references with additional
parameter in invoke function.
This commit is contained in:
Ilmir Usmanov
2018-05-29 13:17:53 +03:00
parent 5869274ff1
commit f94b579d19
82 changed files with 5393 additions and 41 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.contracts.EffectSystem
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -160,7 +161,8 @@ class CallCompleter(
val expectedReturnType =
if (call.isCallableReference()) {
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
if (!TypeUtils.noExpectedType(expectedType) && (expectedType.isFunctionType || expectedType.isSuspendFunctionType))
expectedType.getReturnTypeFromFunctionType()
else TypeUtils.NO_EXPECTED_TYPE
} else expectedType
@@ -211,7 +213,7 @@ class CallCompleter(
}
}
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && (expectedType.isFunctionType || expectedType.isSuspendFunctionType)) {
updateSystemIfNeeded { builder ->
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType())
.forEach { (parameter, argument) ->
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtThisExpression
import org.jetbrains.kotlin.resolve.BindingContext
@@ -59,6 +60,8 @@ object CoroutineSuspendCallChecker : CallChecker {
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
val isCallableReference = resolvedCall.call.callElement.parent is KtCallableReferenceExpression
when {
enclosingSuspendFunction != null -> {
val callElement = resolvedCall.call.callElement as KtExpression
@@ -77,6 +80,9 @@ object CoroutineSuspendCallChecker : CallChecker {
checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
}
isCallableReference -> {
// do nothing: we can get callable reference to suspend function outside suspend context
}
else -> {
when (descriptor) {
is FunctionDescriptor -> context.trace.report(
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.types.expressions
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
@@ -45,6 +46,7 @@ import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.calls.util.createValueParametersForInvokeInFunctionType
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
@@ -585,7 +587,7 @@ class DoubleColonExpressionResolver(
Annotations.EMPTY,
CallableMemberDescriptor.Kind.DECLARATION,
expression.toSourceElement(),
/* isCoroutine = */ false
/* isCoroutine = */ ReflectionTypes.isKSuspendFunction(type)
)
functionDescriptor.initialize(
@@ -636,8 +638,8 @@ class DoubleColonExpressionResolver(
) {
val descriptor =
if (resolutionResults?.isSingleResult == true) resolutionResults.resultingDescriptor as? FunctionDescriptor else null
if (descriptor?.isSuspend == true) {
context.trace.report(UNSUPPORTED.on(expression.callableReference, "Callable references to suspend functions"))
if (descriptor?.isSuspend == true && descriptor is PropertyDescriptor) {
context.trace.report(UNSUPPORTED.on(expression.callableReference, "Callable references to suspend property"))
}
val expressionResult = lhsResult as? DoubleColonLHS.Expression ?: return
@@ -783,7 +785,11 @@ class DoubleColonExpressionResolver(
val returnType = descriptor.returnType ?: return null
val parametersTypes = descriptor.valueParameters.map { it.type }
val parametersNames = descriptor.valueParameters.map { it.name }
return reflectionTypes.getKFunctionType(
return if (descriptor.isSuspend) reflectionTypes.getKSuspendFunctionType(
Annotations.EMPTY, receiverType,
parametersTypes, parametersNames, returnType, descriptor.builtIns
)
else reflectionTypes.getKFunctionType(
Annotations.EMPTY, receiverType,
parametersTypes, parametersNames, returnType, descriptor.builtIns
)