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
@@ -981,8 +981,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
);
ClosureCodegen coroutineCodegen = CoroutineCodegenForLambda.create(this, descriptor, declaration, cv);
ClosureContext closureContext = descriptor.isSuspend() ? this.context.intoCoroutineClosure(
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
descriptor,
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
state.getBindingContext()
),
descriptor, this, state.getTypeMapper()
) : this.context.intoClosure(descriptor, this, typeMapper);
ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen(
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
state, declaration, samType, closureContext,
functionReferenceTarget, strategy, parentCodegen, cv
);
@@ -1120,6 +1128,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (!isCrossinlineLambda) {
v.aconst(null);
}
} else if (superClass != null && superClass.equals(state.getJvmRuntimeTypes().getFunctionReference())) {
// Constructor of callable reference to suspend function does not accept continuation:
// do nothing.
}
else {
assert context.getFunctionDescriptor().isSuspend() : "Coroutines closure must be created only inside suspend functions";
@@ -1128,7 +1139,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
assert continuationValue != null : "Couldn't find a value for continuation parameter of " + context.getFunctionDescriptor();
callGenerator.putCapturedValueOnStack(continuationValue, continuationValue.type, paramIndex++);
callGenerator.putCapturedValueOnStack(continuationValue, continuationValue.type, paramIndex);
}
}
}
@@ -20,11 +20,16 @@ import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.kotlin.resolve.calls.model.DelegatingResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
@@ -73,8 +78,21 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
) {
super(state);
this.resolvedCall = resolvedCall;
this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
this.functionDescriptor = functionDescriptor;
if (resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor &&
((FunctionDescriptor) resolvedCall.getResultingDescriptor()).isSuspend()) {
this.referencedFunction = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
(FunctionDescriptor) resolvedCall.getResultingDescriptor(),
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
state.getBindingContext());
this.functionDescriptor = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
functionDescriptor,
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
state.getBindingContext());
}
else {
this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
this.functionDescriptor = functionDescriptor;
}
this.receiverType = receiverType;
this.receiverValue = receiverValue;
this.isInliningStrategy = isInliningStrategy;
@@ -137,6 +155,18 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
return argumentMap;
}
@NotNull
@Override
public CallableDescriptor getCandidateDescriptor() {
return referencedFunction;
}
@NotNull
@Override
public CallableDescriptor getResultingDescriptor() {
return referencedFunction;
}
};
StackValue result;
@@ -172,7 +202,12 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
Type type = state.getTypeMapper().mapType(parameter);
int localIndex = codegen.myFrameMap.getIndex(parameter);
codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
if (localIndex > 0) {
codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
}
else {
codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(parameter.getIndex() + 1 + receivers, type));
}
}
}
@@ -31,7 +31,7 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
private fun klass(name: String) = lazy { createClass(kotlinJvmInternalPackage, name) }
private val lambda: ClassDescriptor by klass("Lambda")
private val functionReference: ClassDescriptor by klass("FunctionReference")
val functionReference: ClassDescriptor by klass("FunctionReference")
private val localVariableReference: ClassDescriptor by klass("LocalVariableReference")
private val mutableLocalVariableReference: ClassDescriptor by klass("MutableLocalVariableReference")
private val coroutineImplClass by lazy { createClass(kotlinCoroutinesJvmInternalPackage, "CoroutineImpl") }
@@ -94,12 +94,14 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
val receivers = computeExpectedNumberOfReceivers(referencedFunction, isBound)
val functionType = createFunctionType(
referencedFunction.builtIns,
Annotations.EMPTY,
if (isBound) null else referencedFunction.extensionReceiverParameter?.type ?: referencedFunction.dispatchReceiverParameter?.type,
anonymousFunctionDescriptor.valueParameters.drop(receivers).map { it.type },
null,
referencedFunction.returnType!!
referencedFunction.builtIns,
Annotations.EMPTY,
if (isBound) null else referencedFunction.extensionReceiverParameter?.type
?: referencedFunction.dispatchReceiverParameter?.type,
anonymousFunctionDescriptor.valueParameters.drop(receivers).map { it.type },
null,
referencedFunction.returnType!!,
referencedFunction.isSuspend
)
return listOf(functionReference.defaultType, functionType)
@@ -404,6 +404,26 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
ClassDescriptor classDescriptor = recordClassForCallable(expression, callableDescriptor, supertypes, name);
MutableClosure closure = recordClosure(classDescriptor, name);
if (callableDescriptor instanceof SimpleFunctionDescriptor) {
SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) callableDescriptor;
if (functionDescriptor.isSuspend()){
SimpleFunctionDescriptor jvmSuspendFunctionView =
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
functionDescriptor,
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
/*bindingContext*/ null
);
bindingTrace.record(
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
functionDescriptor,
jvmSuspendFunctionView
);
closure.setSuspend(true);
}
}
if (receiverType != null) {
closure.setCaptureReceiverType(receiverType);
}
@@ -332,7 +332,7 @@ class CoroutineCodegenForLambda private constructor(
declaration: KtElement,
classBuilder: ClassBuilder
): ClosureCodegen? {
if (!originalSuspendLambdaDescriptor.isSuspendLambdaOrLocalFunction()) return null
if (!originalSuspendLambdaDescriptor.isSuspendLambdaOrLocalFunction() || declaration is KtCallableReferenceExpression) return null
return CoroutineCodegenForLambda(
expressionCodegen,
@@ -42,10 +42,7 @@ import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentPr
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmBytecodeBinaryVersion;
import org.jetbrains.kotlin.name.*;
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtFunctionLiteral;
import org.jetbrains.kotlin.psi.KtLambdaExpression;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -56,6 +53,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.util.OperatorNameConventions;
@@ -1017,7 +1015,7 @@ public class KotlinTypeMapper {
return OperatorNameConventions.INVOKE.asString();
}
else if (isLocalFunction(descriptor) || isFunctionExpression(descriptor)) {
else if (isLocalFunction(descriptor) || isFunctionExpression(descriptor) || isSuspendFunctionReference(descriptor)) {
return OperatorNameConventions.INVOKE.asString();
}
else {
@@ -1025,6 +1023,13 @@ public class KotlinTypeMapper {
}
}
private static boolean isSuspendFunctionReference(FunctionDescriptor descriptor) {
return descriptor.getSource() instanceof KotlinSourceElement &&
((KotlinSourceElement) descriptor.getSource()).getPsi() instanceof KtCallableReferenceExpression &&
CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor) != null &&
CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor).isSuspend();
}
@NotNull
private static OwnerKind getKindForDefaultImplCall(@NotNull FunctionDescriptor baseMethodDescriptor) {
DeclarationDescriptor containingDeclaration = baseMethodDescriptor.getContainingDeclaration();