Fix for KT-5467: JVM codegen doesn't support capture of many extension receivers

#KT-5467 Fixed
This commit is contained in:
Michael Bogdanov
2014-10-07 13:53:50 +04:00
parent c3cfe33b64
commit bb3f1f1fb7
7 changed files with 61 additions and 24 deletions
@@ -2272,11 +2272,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull
private StackValue generateReceiver(@NotNull CallableDescriptor descriptor) {
if (context.getCallableDescriptorWithReceiver() == descriptor) {
return context.getReceiverExpression(typeMapper);
}
return context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
return context.generateReceiver(descriptor, state, false);
}
// SCRIPT: generate script, move to ScriptingUtil
@@ -3495,6 +3491,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
public StackValue visitThisExpression(@NotNull JetThisExpression expression, StackValue receiver) {
DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
if (descriptor instanceof ClassDescriptor) {
//TODO rewrite with context.lookupInContext()
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true);
}
if (descriptor instanceof CallableDescriptor) {
@@ -1356,8 +1356,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
assert descriptor instanceof CallableDescriptor ||
descriptor instanceof ClassDescriptor : "'This' reference target should be class or callable descriptor but was " + descriptor;
if (context.getCallableDescriptorWithReceiver() != descriptor) {
context.lookupInContext(descriptor, null, state, true);
if (descriptor instanceof ClassDescriptor) {
context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, true);
}
if (descriptor instanceof CallableDescriptor) {
constructorContext.generateReceiver((CallableDescriptor) descriptor, state, true);
}
}
};
@@ -33,7 +33,7 @@ public final class MutableClosure implements CalculatedClosure {
private final ResolvedCall<ConstructorDescriptor> superCall;
private final ClassDescriptor enclosingClass;
private final CallableDescriptor enclosingReceiverDescriptor;
private final CallableDescriptor enclosingFunWithReceiverDescriptor;
private boolean captureThis;
private boolean captureReceiver;
@@ -48,7 +48,7 @@ public final class MutableClosure implements CalculatedClosure {
) {
this.enclosingClass = enclosingClass;
this.superCall = superCall;
this.enclosingReceiverDescriptor = enclosingExtensionMemberForClass(classDescriptor);
this.enclosingFunWithReceiverDescriptor = enclosingExtensionMemberForClass(classDescriptor);
}
@Nullable
@@ -85,18 +85,15 @@ public final class MutableClosure implements CalculatedClosure {
@Override
public JetType getCaptureReceiverType() {
if (captureReceiver) {
//noinspection ConstantConditions
ReceiverParameterDescriptor parameter = enclosingReceiverDescriptor.getExtensionReceiverParameter();
assert parameter != null : "Receiver parameter should exist in " + enclosingReceiverDescriptor;
return parameter.getType();
return getEnclosingReceiverDescriptor().getType();
}
return null;
}
public void setCaptureReceiver() {
if (enclosingReceiverDescriptor == null) {
throw new IllegalStateException();
if (enclosingFunWithReceiverDescriptor == null) {
throw new IllegalStateException("Extension receiver parameter should exist");
}
this.captureReceiver = true;
}
@@ -127,7 +124,10 @@ public final class MutableClosure implements CalculatedClosure {
captureVariables.put(value.getDescriptor(), value);
}
public CallableDescriptor getEnclosingReceiverDescriptor() {
return enclosingReceiverDescriptor;
@NotNull
public ReceiverParameterDescriptor getEnclosingReceiverDescriptor() {
ReceiverParameterDescriptor parameter = enclosingFunWithReceiverDescriptor.getExtensionReceiverParameter();
assert parameter != null : "Receiver parameter should exist in " + enclosingFunWithReceiverDescriptor;
return parameter;
}
}
@@ -112,7 +112,7 @@ public interface LocalLookup {
RECEIVER {
@Override
public boolean isCase(DeclarationDescriptor d) {
return d instanceof CallableDescriptor;
return d instanceof ReceiverParameterDescriptor;
}
@Override
@@ -123,9 +123,11 @@ public interface LocalLookup {
MutableClosure closure,
Type classType
) {
if (closure.getEnclosingReceiverDescriptor() != d) return null;
if (closure.getEnclosingReceiverDescriptor() != d) {
return null;
}
JetType receiverType = ((CallableDescriptor) d).getExtensionReceiverParameter().getType();
JetType receiverType = closure.getEnclosingReceiverDescriptor().getType();
Type type = state.getTypeMapper().mapType(receiverType);
StackValue innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false);
closure.setCaptureReceiver();
@@ -25,14 +25,13 @@ import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.binding.MutableClosure;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Type;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
private final boolean isInliningLambda;
private Label methodStartLabel;
@@ -72,6 +71,15 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
return getParentContext().lookupInContext(d, result, state, ignoreNoOuter);
}
@Nullable
public StackValue generateReceiver(@NotNull CallableDescriptor descriptor, @NotNull GenerationState state, boolean ignoreNoOuter) {
if (getCallableDescriptorWithReceiver() == descriptor) {
return getReceiverExpression(state.getTypeMapper());
}
ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
return lookupInContext(parameter, StackValue.local(0, OBJECT_TYPE), state, ignoreNoOuter);
}
@Override
public boolean isStatic() {
return getParentContext().isStatic();
@@ -0,0 +1,20 @@
fun String.foo() : String {
fun Int.bar() : String {
fun Long.baz() : String {
val x = this@foo
val y = this@bar
val z = this@baz
return "$x $y $z"
}
return 0L.baz()
}
return 42.bar()
}
fun box() : String {
val result = "OK".foo()
if (result != "OK 42 0") return "fail: $result"
return "OK"
}
@@ -2813,6 +2813,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt5467.kt")
public void testKt5467() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt5467.kt");
doTest(fileName);
}
@TestMetadata("kt606.kt")
public void testKt606() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt606.kt");