Use ResolvedCall to generate callable reference receiver
This will be helpful in supporting KT-15667
This commit is contained in:
@@ -2692,35 +2692,45 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
public StackValue visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, StackValue data) {
|
public StackValue visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, StackValue data) {
|
||||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression.getCallableReference(), bindingContext);
|
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression.getCallableReference(), bindingContext);
|
||||||
|
|
||||||
KotlinType receiverExpressionType = expressionJetType(expression.getReceiverExpression());
|
StackValue receiver = generateCallableReferenceReceiver(resolvedCall);
|
||||||
Type receiverAsmType = receiverExpressionType != null ? asmType(receiverExpressionType) : null;
|
|
||||||
StackValue receiverValue =
|
|
||||||
receiverExpressionType != null ? StackValue.coercion(gen(expression.getReceiverExpression()), receiverAsmType) : null;
|
|
||||||
|
|
||||||
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||||
if (functionDescriptor != null) {
|
if (functionDescriptor != null) {
|
||||||
FunctionReferenceGenerationStrategy strategy =
|
FunctionReferenceGenerationStrategy strategy = new FunctionReferenceGenerationStrategy(
|
||||||
new FunctionReferenceGenerationStrategy(state, functionDescriptor, resolvedCall, receiverAsmType, null, false);
|
state, functionDescriptor, resolvedCall, receiver != null ? receiver.type : null, null, false
|
||||||
|
);
|
||||||
|
|
||||||
return genClosure(
|
return genClosure(
|
||||||
expression, functionDescriptor, strategy, null,
|
expression, functionDescriptor, strategy, null,
|
||||||
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), receiverValue
|
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), receiver
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(expression);
|
|
||||||
return generatePropertyReference(
|
return generatePropertyReference(
|
||||||
expression, variableDescriptor, (VariableDescriptor) resolvedCall.getResultingDescriptor(),
|
expression, getVariableDescriptorNotNull(expression),
|
||||||
receiverAsmType, receiverValue
|
(VariableDescriptor) resolvedCall.getResultingDescriptor(), receiver
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private StackValue generateCallableReferenceReceiver(@NotNull ResolvedCall<?> resolvedCall) {
|
||||||
|
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||||
|
if (descriptor.getExtensionReceiverParameter() == null && descriptor.getDispatchReceiverParameter() == null) return null;
|
||||||
|
|
||||||
|
ReceiverValue dispatchReceiver = resolvedCall.getDispatchReceiver();
|
||||||
|
ReceiverValue extensionReceiver = resolvedCall.getExtensionReceiver();
|
||||||
|
assert dispatchReceiver == null || extensionReceiver == null : "Cannot generate reference with both receivers: " + descriptor;
|
||||||
|
ReceiverValue receiver = dispatchReceiver != null ? dispatchReceiver : extensionReceiver;
|
||||||
|
if (receiver == null || receiver instanceof TransientReceiver) return null;
|
||||||
|
|
||||||
|
return StackValue.coercion(generateReceiverValue(receiver, false), asmType(receiver.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private StackValue generatePropertyReference(
|
private StackValue generatePropertyReference(
|
||||||
@NotNull KtElement element,
|
@NotNull KtElement element,
|
||||||
@NotNull VariableDescriptor variableDescriptor,
|
@NotNull VariableDescriptor variableDescriptor,
|
||||||
@NotNull VariableDescriptor target,
|
@NotNull VariableDescriptor target,
|
||||||
@Nullable Type receiverAsmType,
|
|
||||||
@Nullable StackValue receiverValue
|
@Nullable StackValue receiverValue
|
||||||
) {
|
) {
|
||||||
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
|
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
|
||||||
@@ -2731,17 +2741,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
element.getContainingFile()
|
element.getContainingFile()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Type receiverAsmType = receiverValue != null ? receiverValue.type : null;
|
||||||
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
|
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
|
||||||
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
|
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
|
||||||
element, classBuilder, variableDescriptor, target, receiverAsmType
|
element, classBuilder, variableDescriptor, target, receiverAsmType
|
||||||
);
|
);
|
||||||
codegen.generate();
|
codegen.generate();
|
||||||
|
|
||||||
return codegen.putInstanceOnStack(receiverValue == null ? null : () -> {
|
return codegen.putInstanceOnStack(receiverValue);
|
||||||
assert receiverAsmType != null : "Receiver type should not be null when receiver value is not null: " + receiverValue;
|
|
||||||
receiverValue.put(receiverAsmType, v);
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -3670,7 +3677,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
// container class (where the PropertyReferenceNImpl instance is created), copy and adapt it at the call site
|
// container class (where the PropertyReferenceNImpl instance is created), copy and adapt it at the call site
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
StackValue value = context.getFunctionDescriptor().isInline()
|
StackValue value = context.getFunctionDescriptor().isInline()
|
||||||
? generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null)
|
? generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null)
|
||||||
: PropertyCodegen.getDelegatedPropertyMetadata(variableDescriptor, bindingContext);
|
: PropertyCodegen.getDelegatedPropertyMetadata(variableDescriptor, bindingContext);
|
||||||
value.put(K_PROPERTY_TYPE, v);
|
value.put(K_PROPERTY_TYPE, v);
|
||||||
metadataVar.storeSelector(K_PROPERTY_TYPE, v);
|
metadataVar.storeSelector(K_PROPERTY_TYPE, v);
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ class PropertyReferenceCodegen(
|
|||||||
writeSyntheticClassMetadata(v, state)
|
writeSyntheticClassMetadata(v, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putInstanceOnStack(receiverValue: (() -> Unit)?): StackValue {
|
fun putInstanceOnStack(receiverValue: StackValue?): StackValue {
|
||||||
return StackValue.operation(wrapperMethod.returnType) { iv ->
|
return StackValue.operation(wrapperMethod.returnType) { iv ->
|
||||||
if (JvmCodegenUtil.isConst(closure)) {
|
if (JvmCodegenUtil.isConst(closure)) {
|
||||||
assert(receiverValue == null) { "No receiver expected for unbound property reference: $classDescriptor" }
|
assert(receiverValue == null) { "No receiver expected for unbound property reference: $classDescriptor" }
|
||||||
@@ -175,7 +175,7 @@ class PropertyReferenceCodegen(
|
|||||||
assert(receiverValue != null) { "Receiver expected for bound property reference: $classDescriptor" }
|
assert(receiverValue != null) { "Receiver expected for bound property reference: $classDescriptor" }
|
||||||
iv.anew(asmType)
|
iv.anew(asmType)
|
||||||
iv.dup()
|
iv.dup()
|
||||||
receiverValue!!()
|
receiverValue!!.put(receiverValue.type, iv)
|
||||||
iv.invokespecial(asmType.internalName, "<init>", constructor.descriptor, false)
|
iv.invokespecial(asmType.internalName, "<init>", constructor.descriptor, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -57,6 +57,8 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
|||||||
import org.jetbrains.kotlin.resolve.constants.EnumValue;
|
import org.jetbrains.kotlin.resolve.constants.EnumValue;
|
||||||
import org.jetbrains.kotlin.resolve.constants.NullValue;
|
import org.jetbrains.kotlin.resolve.constants.NullValue;
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
@@ -332,12 +334,18 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
if (referencedFunction == null) return;
|
if (referencedFunction == null) return;
|
||||||
CallableDescriptor target = referencedFunction.getResultingDescriptor();
|
CallableDescriptor target = referencedFunction.getResultingDescriptor();
|
||||||
|
|
||||||
|
ReceiverValue extensionReceiver = referencedFunction.getExtensionReceiver();
|
||||||
|
ReceiverValue dispatchReceiver = referencedFunction.getDispatchReceiver();
|
||||||
|
|
||||||
|
// TransientReceiver corresponds to an unbound reference, other receiver values -- to bound references
|
||||||
|
KotlinType receiverType =
|
||||||
|
dispatchReceiver != null && !(dispatchReceiver instanceof TransientReceiver) ? dispatchReceiver.getType() :
|
||||||
|
extensionReceiver != null && !(extensionReceiver instanceof TransientReceiver) ? extensionReceiver.getType() :
|
||||||
|
null;
|
||||||
|
|
||||||
CallableDescriptor callableDescriptor;
|
CallableDescriptor callableDescriptor;
|
||||||
Collection<KotlinType> supertypes;
|
Collection<KotlinType> supertypes;
|
||||||
|
|
||||||
KtExpression receiverExpression = expression.getReceiverExpression();
|
|
||||||
KotlinType receiverType = receiverExpression != null ? bindingContext.getType(receiverExpression) : null;
|
|
||||||
|
|
||||||
if (target instanceof FunctionDescriptor) {
|
if (target instanceof FunctionDescriptor) {
|
||||||
callableDescriptor = bindingContext.get(FUNCTION, expression);
|
callableDescriptor = bindingContext.get(FUNCTION, expression);
|
||||||
if (callableDescriptor == null) return;
|
if (callableDescriptor == null) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user