Use ResolvedCall to generate callable reference receiver

This will be helpful in supporting KT-15667
This commit is contained in:
Alexander Udalov
2017-08-24 17:09:51 +03:00
parent c420e2bfa5
commit cdda5d39e5
3 changed files with 37 additions and 22 deletions
@@ -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)
} }
} }
@@ -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;