From 06f2cbc891f9603c1bd8cc22120e89c3609df036 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 6 Jul 2012 20:54:36 +0400 Subject: [PATCH] object literals now capture expressions from 'by' delegate specifier #KT-2224 Fixed --- .../codegen/ImplementationBodyCodegen.java | 73 ++++++++++++------- .../jet/codegen/ObjectOrClosureCodegen.java | 3 +- .../testData/codegen/regressions/kt2224.kt | 44 +++++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 5 ++ 4 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 compiler/testData/codegen/regressions/kt2224.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 63361c4af01..780086f0389 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -493,6 +493,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { constructorMethod = callableMethod.getSignature(); } + if (context.closure != null) { + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + if (specifier != superCall && specifier instanceof JetDelegatorByExpressionSpecifier) { + JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); + delegateExpression.accept(new JetVisitorVoid() { + @Override + public void visitJetElement(JetElement e) { + e.acceptChildren(this); + } + + @Override + public void visitSimpleNameExpression(JetSimpleNameExpression expr) { + context.closure.lookupInContext(bindingContext.get(BindingContext.REFERENCE_TARGET, expr), null); + } + }); + } + } + } + ObjectOrClosureCodegen closure = context.closure; int firstSuperArgument = -1; final LinkedList consArgTypes = new LinkedList(constructorMethod.getKotlinParameterTypes()); @@ -638,33 +657,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateDelegatorToConstructorCall(iv, codegen, (JetDelegatorToSuperCall) superCall, constructorDescriptor1, frameMap, firstSuperArgument); } - int n = 0; - for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { - if (specifier == superCall) - continue; - - if (specifier instanceof JetDelegatorByExpressionSpecifier) { - iv.load(0, classType); - codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression()); - - JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); - assert superType != null; - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - String delegateField = "$delegate_" + (n++); - Type fieldType = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.VALUE); - String fieldDesc = fieldType.getDescriptor(); - v.newField(specifier, ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null); - StackValue field = StackValue.field(fieldType, classname, delegateField, false); - field.store(fieldType, iv); - - JetClass superClass = (JetClass) BindingContextUtils.classDescriptorToDeclaration(bindingContext, superClassDescriptor); - final CodegenContext delegateContext = context.intoClass(superClassDescriptor, - new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), - typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName()), state.getInjector().getJetTypeMapper()); - generateDelegates(superClass, delegateContext, field); - } - } - final ClassDescriptor outerDescriptor = typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor); final boolean hasOuterThis = typeMapper.hasThis0(descriptor) && outerDescriptor != null; if (hasOuterThis) { @@ -702,6 +694,33 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + int n = 0; + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + if (specifier == superCall) + continue; + + if (specifier instanceof JetDelegatorByExpressionSpecifier) { + iv.load(0, classType); + codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression()); + + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + String delegateField = "$delegate_" + (n++); + Type fieldType = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.VALUE); + String fieldDesc = fieldType.getDescriptor(); + v.newField(specifier, ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null); + StackValue field = StackValue.field(fieldType, classname, delegateField, false); + field.store(fieldType, iv); + + JetClass superClass = (JetClass) BindingContextUtils.classDescriptorToDeclaration(bindingContext, superClassDescriptor); + final CodegenContext delegateContext = context.intoClass(superClassDescriptor, + new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), + typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName()), state.getInjector().getJetTypeMapper()); + generateDelegates(superClass, delegateContext, field); + } + } + int curParam = 0; List constructorParameters = getPrimaryConstructorParameters(); for (JetParameter parameter : constructorParameters) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java index 1ef00ab8f84..3b6f3b5bea2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; import org.jetbrains.jet.lang.psi.JetElement; @@ -48,7 +49,7 @@ public class ObjectOrClosureCodegen { this.state = state; } - public StackValue lookupInContext(DeclarationDescriptor d, StackValue result) { + public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result) { EnclosedValueDescriptor answer = closure.get(d); if (answer != null) { StackValue innerValue = answer.getInnerValue(); diff --git a/compiler/testData/codegen/regressions/kt2224.kt b/compiler/testData/codegen/regressions/kt2224.kt new file mode 100644 index 00000000000..83c8cb44b86 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt2224.kt @@ -0,0 +1,44 @@ +trait A { + fun foo(): Int +} + +class B1 : A { + override fun foo() = 10 +} + +class B2(val z: Int) : A { + override fun foo() = z +} + + + +fun f1(b: B1): Int { + val o = object : A by b { } + return o.foo() +} + +fun f2(b: B2): Int { + val o = object : A by B2(b.z) { } + return o.foo() +} + +fun f3(b: B2, mult: Int): Int { + val o = object : A by B2(mult * b.z) { } + return o.foo() +} + +fun f4(b: B1, x: Int, y: Int, z: Int): Int { + val o = object : A by b { + fun bar() = x + y + z + } + return o.foo() +} + + +fun box(): String { + if (f1(B1()) != 10) return "fail #1" + if (f2(B2(239)) != 239) return "fail #2" + if (f3(B2(239), 2) != 239*2) return "fail #3" + if (f4(B1(), 1, 2, 3) != 10) return "fail #4" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 8dbf910077b..9321eaaa26b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -446,4 +446,9 @@ public class ClassGenTest extends CodegenTestCase { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); blackBoxFile("regressions/kt1891.kt"); } + + public void testKt2224() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("regressions/kt2224.kt"); + } }