Introduce AdaptedFunctionReference runtime class

It's used as a superclass for anonymous classes for adapted function
references. Its main feature is that it _doesn't_ inherit from KFunction
(as opposed to FunctionReference), as per the decision to postpone
reflection support for adapted function references in KT-36024.

 #KT-36024 Fixed
This commit is contained in:
Alexander Udalov
2020-04-03 21:14:00 +02:00
parent d1c5a42124
commit 0681231e99
14 changed files with 178 additions and 85 deletions
@@ -74,7 +74,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
protected final Type asmType;
protected final int visibilityFlag;
private final boolean shouldHaveBoundReferenceReceiver;
private final boolean isRegularFunctionReference;
private final boolean isLegacyFunctionReference;
private final boolean isOptimizedFunctionReference;
private final boolean isAdaptedFunctionReference;
@@ -129,7 +129,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
this.shouldHaveBoundReferenceReceiver = CallableReferenceUtilKt.isForBoundCallableReference(closure);
ClassifierDescriptor superClassDescriptor = superClassType.getConstructor().getDeclarationDescriptor();
this.isRegularFunctionReference =
this.isLegacyFunctionReference =
functionReferenceTarget != null &&
superClassDescriptor == state.getJvmRuntimeTypes().getFunctionReference();
this.isOptimizedFunctionReference =
@@ -137,7 +137,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
superClassDescriptor == state.getJvmRuntimeTypes().getFunctionReferenceImpl();
this.isAdaptedFunctionReference =
functionReferenceTarget != null &&
superClassDescriptor == state.getJvmRuntimeTypes().getLambda();
superClassDescriptor == state.getJvmRuntimeTypes().getAdaptedFunctionReference();
this.asmType = typeMapper.mapClass(classDescriptor);
@@ -199,29 +199,15 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
protected void generateClosureBody() {
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), funDescriptor, strategy);
if (isRegularFunctionReference) {
if (isLegacyFunctionReference) {
generateFunctionReferenceMethods(functionReferenceTarget);
}
if (shouldHaveBoundReferenceReceiver && isAdaptedFunctionReference) {
generateBoundAdaptedCallableReferenceReceiverField();
}
functionCodegen.generateDefaultIfNeeded(
context.intoFunction(funDescriptor), funDescriptor, context.getContextKind(), DefaultParameterValueLoader.DEFAULT, null
);
}
private void generateBoundAdaptedCallableReferenceReceiverField() {
v.newField(
JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor),
ACC_PRIVATE,
BOUND_REFERENCE_RECEIVER,
OBJECT_TYPE.getDescriptor(),
null, null
);
}
protected void generateBridges() {
FunctionDescriptor erasedInterfaceFunction;
if (samType == null) {
@@ -522,20 +508,19 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
iv.load(0, superClassAsmType);
List<Type> superCtorArgTypes = new ArrayList<>();
if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) ||
superClassAsmType.equals(FUNCTION_REFERENCE_IMPL) ||
if (superClassAsmType.equals(LAMBDA) || functionReferenceTarget != null ||
CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName())
) {
int arity = calculateArity();
iv.iconst(arity);
superCtorArgTypes.add(Type.INT_TYPE);
if (shouldHaveBoundReferenceReceiver && !isAdaptedFunctionReference) {
if (shouldHaveBoundReferenceReceiver) {
CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(
iv, boundReceiverParameterIndex, boundReceiverType, boundReceiverKotlinType
);
superCtorArgTypes.add(OBJECT_TYPE);
}
if (isOptimizedFunctionReference) {
if (isOptimizedFunctionReference || isAdaptedFunctionReference) {
assert functionReferenceTarget != null : "No function reference target: " + funDescriptor;
generateCallableReferenceDeclarationContainerClass(iv, functionReferenceTarget, state);
iv.aconst(functionReferenceTarget.getName().asString());
@@ -558,19 +543,6 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
Type.getMethodDescriptor(Type.VOID_TYPE, superCtorArgTypes.toArray(new Type[0])), false
);
// Bound adapted function references store receiver in a separate field.
if (shouldHaveBoundReferenceReceiver && isAdaptedFunctionReference) {
iv.load(0, superClassAsmType);
CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(
iv, boundReceiverParameterIndex, boundReceiverType, boundReceiverKotlinType
);
iv.putfield(
asmType.getInternalName(),
BOUND_REFERENCE_RECEIVER,
OBJECT_TYPE.getDescriptor()
);
}
iv.visitInsn(RETURN);
FunctionCodegen.endVisit(iv, "constructor", element);
@@ -43,9 +43,10 @@ class JvmRuntimeTypes(
private fun propertyClasses(prefix: String, suffix: String): Lazy<List<ClassDescriptor>> =
lazy { (0..2).map { i -> createClass(kotlinJvmInternalPackage, prefix + i + suffix) } }
val lambda: ClassDescriptor by internal("Lambda")
private val lambda: ClassDescriptor by internal("Lambda")
val functionReference: ClassDescriptor by internal("FunctionReference")
val functionReferenceImpl: ClassDescriptor by internal("FunctionReferenceImpl")
val adaptedFunctionReference: ClassDescriptor by internal("AdaptedFunctionReference")
private val localVariableReference: ClassDescriptor by internal("LocalVariableReference")
private val mutableLocalVariableReference: ClassDescriptor by internal("MutableLocalVariableReference")
@@ -152,7 +153,7 @@ class JvmRuntimeTypes(
val suspendFunctionType = if (referencedFunction.isSuspend) suspendFunctionInterface?.defaultType else null
val superClass = when {
isAdaptedCallableReference -> lambda
isAdaptedCallableReference -> adaptedFunctionReference
generateOptimizedCallableReferenceSuperClasses -> functionReferenceImpl
else -> functionReference
}