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) {
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)
}
}
@@ -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;