From df03eb533003f9167c53f9375626d4cdea55bfa3 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Fri, 8 Nov 2013 13:58:58 +0400 Subject: [PATCH] KT-4173: Can't pass a non-trivial closure to a super-call for object expression #KT-4173 Fixed --- .../binding/CodegenAnnotatingVisitor.java | 93 ++++++++++++++----- compiler/testData/codegen/box/super/kt4173.kt | 18 ++++ .../testData/codegen/box/super/kt4173_2.kt | 20 ++++ .../testData/codegen/box/super/kt4173_3.kt | 27 ++++++ .../BlackBoxCodegenTestGenerated.java | 15 +++ 5 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 compiler/testData/codegen/box/super/kt4173.kt create mode 100644 compiler/testData/codegen/box/super/kt4173_2.kt create mode 100644 compiler/testData/codegen/box/super/kt4173_3.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java index 7794f5f7caf..20ee44dad04 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java @@ -44,10 +44,7 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.jetbrains.jet.codegen.CodegenUtil.peekFromStack; import static org.jetbrains.jet.codegen.FunctionTypesUtil.getSuperTypeForClosure; @@ -59,9 +56,32 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { private static final TokenSet BINARY_OPERATIONS = TokenSet.orSet( AUGMENTED_ASSIGNMENTS, TokenSet.create(PLUS, MINUS, MUL, DIV, PERC, RANGE, LT, GT, LTEQ, GTEQ, IDENTIFIER)); + private static class ClassDescriptorWithState { + + private boolean isDelegationToSuperCall; + + private ClassDescriptor descriptor; + + public ClassDescriptorWithState(ClassDescriptor descriptor) { + this.descriptor = descriptor; + } + + public boolean isDelegationToSuperCall() { + return isDelegationToSuperCall; + } + + public void setDelegationToSuperCall(boolean isDelegationToSuperCall) { + this.isDelegationToSuperCall = isDelegationToSuperCall; + } + + public ClassDescriptor getDescriptor() { + return descriptor; + } + } + private final Map anonymousSubclassesCount = new HashMap(); - private final Stack classStack = new Stack(); + private final Stack classStack = new Stack(); private final Stack nameStack = new Stack(); private final BindingTrace bindingTrace; private final BindingContext bindingContext; @@ -129,7 +149,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { if (file.isScript()) { //noinspection ConstantConditions ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, bindingContext.get(SCRIPT, file.getScript())); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); //noinspection ConstantConditions nameStack.push(asmTypeForScriptPsi(bindingContext, file.getScript()).getInternalName()); } @@ -139,7 +159,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { file.acceptChildren(this); nameStack.pop(); if (file.isScript()) { - classStack.pop(); + popClassDescriptor(); } } @@ -154,7 +174,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { super.visitEnumEntry(enumEntry); } else { - Type asmType = bindingTrace.get(ASM_TYPE, peekFromStack(classStack)); + Type asmType = bindingTrace.get(ASM_TYPE, getOuterClassDescriptor()); assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType); bindingTrace.record(ASM_TYPE, descriptor, asmType); } @@ -168,11 +188,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { String name = peekFromStack(nameStack) + JvmAbi.CLASS_OBJECT_SUFFIX; recordClosure(classObject, classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); nameStack.push(name); super.visitClassObject(classObject); nameStack.pop(); - classStack.pop(); + popClassDescriptor(); } @Override @@ -188,11 +208,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { String name = getName(classDescriptor); recordClosure(declaration, classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); nameStack.push(name); super.visitObjectDeclaration(declaration); nameStack.pop(); - classStack.pop(); + popClassDescriptor(); } } @@ -205,11 +225,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { String name = getName(classDescriptor); recordClosure(klass, classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); nameStack.push(name); super.visitClass(klass); nameStack.pop(); - classStack.pop(); + popClassDescriptor(); } private String getName(ClassDescriptor classDescriptor) { @@ -230,12 +250,12 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { String name = inventAnonymousClassName(expression.getObjectDeclaration()); recordClosure(expression.getObjectDeclaration(), classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); //noinspection ConstantConditions nameStack.push(bindingContext.get(ASM_TYPE, classDescriptor).getInternalName()); super.visitObjectLiteralExpression(expression); nameStack.pop(); - classStack.pop(); + popClassDescriptor(); } @Override @@ -251,13 +271,41 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType); recordClosure(functionLiteral, classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); nameStack.push(name); super.visitFunctionLiteralExpression(expression); nameStack.pop(); + popClassDescriptor(); + } + + private void pushClassDescriptor(ClassDescriptor classDescriptor) { + classStack.push(new ClassDescriptorWithState(classDescriptor)); + } + + private void popClassDescriptor() { classStack.pop(); } + private ClassDescriptor getOuterClassDescriptor() { + ListIterator iterator = classStack.listIterator(classStack.size()); + while(iterator.hasPrevious()) { + ClassDescriptorWithState previous = iterator.previous(); + if (!previous.isDelegationToSuperCall()) {//find last not delegated to super call + return previous.getDescriptor(); + } + } + return null; + } + + @Override + public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { + ClassDescriptorWithState state = peekFromStack(classStack); + assert state != null : "Class descriptor should be recorded before " + call + " processing"; + state.setDelegationToSuperCall(true); + super.visitDelegationToSuperCallSpecifier(call); + state.setDelegationToSuperCall(false); + } + @Override public void visitCallableReferenceExpression(JetCallableReferenceExpression expression) { FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); @@ -273,19 +321,20 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType); recordClosure(expression, classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); nameStack.push(name); super.visitCallableReferenceExpression(expression); nameStack.pop(); - classStack.pop(); + popClassDescriptor(); } + private void recordClosure( @NotNull JetElement element, @NotNull ClassDescriptor classDescriptor, @NotNull String name ) { - CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, peekFromStack(classStack), + CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, getOuterClassDescriptor(), Type.getObjectType(name)); } @@ -324,11 +373,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType); recordClosure(function, classDescriptor, name); - classStack.push(classDescriptor); + pushClassDescriptor(classDescriptor); nameStack.push(name); super.visitNamedFunction(function); nameStack.pop(); - classStack.pop(); + popClassDescriptor(); } } diff --git a/compiler/testData/codegen/box/super/kt4173.kt b/compiler/testData/codegen/box/super/kt4173.kt new file mode 100644 index 00000000000..12ca4f5c6ee --- /dev/null +++ b/compiler/testData/codegen/box/super/kt4173.kt @@ -0,0 +1,18 @@ +open class C(val f: () -> Unit) { + fun test() { + f() + } +} + +class B(var x: Int) { + fun foo() { + object : C({x = 3}) {}.test() + } +} + + +fun box() : String { + val b = B(1) + b.foo() + return if (b.x != 3) "fail: b.x = ${b.x}" else "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/super/kt4173_2.kt b/compiler/testData/codegen/box/super/kt4173_2.kt new file mode 100644 index 00000000000..3bc81264f0c --- /dev/null +++ b/compiler/testData/codegen/box/super/kt4173_2.kt @@ -0,0 +1,20 @@ +open class X(var s: ()-> Unit) + +open class C(val f: X) { + fun test() { + f.s() + } +} + +class B(var x: Int) { + fun foo() { + object : C(object: X({x = 3}) {}) {}.test() + } +} + + +fun box() : String { + val b = B(1) + b.foo() + return if (b.x != 3) "fail: b.x = ${b.x}" else "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/super/kt4173_3.kt b/compiler/testData/codegen/box/super/kt4173_3.kt new file mode 100644 index 00000000000..8c23cf83f28 --- /dev/null +++ b/compiler/testData/codegen/box/super/kt4173_3.kt @@ -0,0 +1,27 @@ +open class C(s: Int) { + fun test() { + + } +} + +class B(var x: Int) { + fun foo() { + class A(val a: Int) : C({a}()) { + + } + A(11).test() + + + class B(val a: Int) : C(a) { + } + + B(11).test() + } +} + + +fun box() : String { + val b = B(1) + b.foo() + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index f9419f97ff1..9548b9716f6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -4200,6 +4200,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/super/kt3538.kt"); } + @TestMetadata("kt4173.kt") + public void testKt4173() throws Exception { + doTest("compiler/testData/codegen/box/super/kt4173.kt"); + } + + @TestMetadata("kt4173_2.kt") + public void testKt4173_2() throws Exception { + doTest("compiler/testData/codegen/box/super/kt4173_2.kt"); + } + + @TestMetadata("kt4173_3.kt") + public void testKt4173_3() throws Exception { + doTest("compiler/testData/codegen/box/super/kt4173_3.kt"); + } + @TestMetadata("multipleSuperTraits.kt") public void testMultipleSuperTraits() throws Exception { doTest("compiler/testData/codegen/box/super/multipleSuperTraits.kt");