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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
-4
@@ -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)
|
||||
|
||||
+20
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user