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) {
|
||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression.getCallableReference(), bindingContext);
|
||||
|
||||
KotlinType receiverExpressionType = expressionJetType(expression.getReceiverExpression());
|
||||
Type receiverAsmType = receiverExpressionType != null ? asmType(receiverExpressionType) : null;
|
||||
StackValue receiverValue =
|
||||
receiverExpressionType != null ? StackValue.coercion(gen(expression.getReceiverExpression()), receiverAsmType) : null;
|
||||
StackValue receiver = generateCallableReferenceReceiver(resolvedCall);
|
||||
|
||||
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
if (functionDescriptor != null) {
|
||||
FunctionReferenceGenerationStrategy strategy =
|
||||
new FunctionReferenceGenerationStrategy(state, functionDescriptor, resolvedCall, receiverAsmType, null, false);
|
||||
FunctionReferenceGenerationStrategy strategy = new FunctionReferenceGenerationStrategy(
|
||||
state, functionDescriptor, resolvedCall, receiver != null ? receiver.type : null, null, false
|
||||
);
|
||||
|
||||
return genClosure(
|
||||
expression, functionDescriptor, strategy, null,
|
||||
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), receiverValue
|
||||
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), receiver
|
||||
);
|
||||
}
|
||||
|
||||
VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(expression);
|
||||
return generatePropertyReference(
|
||||
expression, variableDescriptor, (VariableDescriptor) resolvedCall.getResultingDescriptor(),
|
||||
receiverAsmType, receiverValue
|
||||
expression, getVariableDescriptorNotNull(expression),
|
||||
(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
|
||||
private StackValue generatePropertyReference(
|
||||
@NotNull KtElement element,
|
||||
@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull VariableDescriptor target,
|
||||
@Nullable Type receiverAsmType,
|
||||
@Nullable StackValue receiverValue
|
||||
) {
|
||||
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
|
||||
@@ -2731,17 +2741,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
element.getContainingFile()
|
||||
);
|
||||
|
||||
Type receiverAsmType = receiverValue != null ? receiverValue.type : null;
|
||||
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
|
||||
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
|
||||
element, classBuilder, variableDescriptor, target, receiverAsmType
|
||||
);
|
||||
codegen.generate();
|
||||
|
||||
return codegen.putInstanceOnStack(receiverValue == null ? null : () -> {
|
||||
assert receiverAsmType != null : "Receiver type should not be null when receiver value is not null: " + receiverValue;
|
||||
receiverValue.put(receiverAsmType, v);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
return codegen.putInstanceOnStack(receiverValue);
|
||||
}
|
||||
|
||||
@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
|
||||
//noinspection ConstantConditions
|
||||
StackValue value = context.getFunctionDescriptor().isInline()
|
||||
? generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null)
|
||||
? generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null)
|
||||
: PropertyCodegen.getDelegatedPropertyMetadata(variableDescriptor, bindingContext);
|
||||
value.put(K_PROPERTY_TYPE, v);
|
||||
metadataVar.storeSelector(K_PROPERTY_TYPE, v);
|
||||
|
||||
@@ -165,7 +165,7 @@ class PropertyReferenceCodegen(
|
||||
writeSyntheticClassMetadata(v, state)
|
||||
}
|
||||
|
||||
fun putInstanceOnStack(receiverValue: (() -> Unit)?): StackValue {
|
||||
fun putInstanceOnStack(receiverValue: StackValue?): StackValue {
|
||||
return StackValue.operation(wrapperMethod.returnType) { iv ->
|
||||
if (JvmCodegenUtil.isConst(closure)) {
|
||||
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" }
|
||||
iv.anew(asmType)
|
||||
iv.dup()
|
||||
receiverValue!!()
|
||||
receiverValue!!.put(receiverValue.type, iv)
|
||||
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.NullValue;
|
||||
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.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -332,12 +334,18 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
if (referencedFunction == null) return;
|
||||
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;
|
||||
Collection<KotlinType> supertypes;
|
||||
|
||||
KtExpression receiverExpression = expression.getReceiverExpression();
|
||||
KotlinType receiverType = receiverExpression != null ? bindingContext.getType(receiverExpression) : null;
|
||||
|
||||
if (target instanceof FunctionDescriptor) {
|
||||
callableDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
if (callableDescriptor == null) return;
|
||||
|
||||
Reference in New Issue
Block a user