From 2edb89b5c52cc20a12de975dbb48deb7a0ee0ac0 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 2 Nov 2012 16:50:46 +0400 Subject: [PATCH] Refactor mysterious code in ExpressionCodegen 'super' receiver is now generated in visitSuperExpression() --- .../jet/codegen/ExpressionCodegen.java | 90 ++++++++++--------- .../codegen/super/innerClassLabeledSuper.kt | 38 ++++++++ .../super/innerClassLabeledSuperProperty.kt | 38 ++++++++ .../codegen/super/multipleSuperTraits.kt | 13 +++ .../jetbrains/jet/codegen/SuperGenTest.java | 12 +++ 5 files changed, 151 insertions(+), 40 deletions(-) create mode 100644 compiler/testData/codegen/super/innerClassLabeledSuper.kt create mode 100644 compiler/testData/codegen/super/innerClassLabeledSuperProperty.kt create mode 100644 compiler/testData/codegen/super/multipleSuperTraits.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 06d07d9554c..e748ff55a09 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -291,14 +291,20 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) { - final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); - if (descriptor instanceof ClassDescriptor) { - return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, true); - } - else { - JetType type = context.getThisDescriptor().getDefaultType(); - return StackValue.local(0, asmType(type)); + return StackValue.thisOrOuter(this, getSuperCallLabelTarget(expression), true); + } + + private ClassDescriptor getSuperCallLabelTarget(JetSuperExpression expression) { + PsiElement labelPsi = bindingContext.get(BindingContext.LABEL_TARGET, expression.getTargetLabel()); + ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, labelPsi); + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); + // "super@labelTarget" + if (labelTarget != null) { + return labelTarget; } + assert descriptor instanceof ClassDescriptor : "Don't know how to generate super-call to not a class"; + ClassDescriptor target = getParentContextSubclassOf((ClassDescriptor) descriptor).getThisDescriptor(); + return target; } @NotNull @@ -1738,38 +1744,11 @@ public class ExpressionCodegen extends JetVisitor implem ResolvedCall resolvedCall ) { FunctionDescriptor fd = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); - boolean superCall = false; - ReceiverValue explicitReceiver = call.getExplicitReceiver(); - if (explicitReceiver instanceof ExpressionReceiver) { - final JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression(); - if (receiverExpression instanceof JetSuperExpression) { - superCall = true; - receiver = StackValue.thisOrOuter(this, context.getThisDescriptor(), true); - JetSuperExpression superExpression = (JetSuperExpression) receiverExpression; - PsiElement enclosingElement = bindingContext.get(BindingContext.LABEL_TARGET, superExpression.getTargetLabel()); - ClassDescriptor enclosed = (ClassDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, enclosingElement); - if (!isInterface(fd.getContainingDeclaration())) { - if (enclosed == null) { - enclosed = (ClassDescriptor) fd.getContainingDeclaration(); - } - if (enclosed != context.getThisDescriptor()) { - CodegenContext c = context; - //noinspection ConstantConditions - while (true) { - if ((c instanceof ClassContext || c instanceof AnonymousClassContext) && - DescriptorUtils.isSubclass(c.getThisDescriptor(), enclosed)) { - break; - } - c = c.getParentContext(); - assert c != null; - } - fd = unwrapFakeOverride(fd); - fd = (FunctionDescriptor) c.getAccessor(fd); - superCall = false; - receiver = StackValue.thisOrOuter(this, enclosed, true); - } - } - } + boolean superCall = isSuperCall(call); + + if (superCall && !isInterface(fd.getContainingDeclaration())) { + CodegenContext c = getParentContextSubclassOf((ClassDescriptor) fd.getContainingDeclaration()); + fd = (FunctionDescriptor) c.getAccessor(unwrapFakeOverride(fd)); } fd = accessableFunctionDescriptor(fd); @@ -1801,6 +1780,35 @@ public class ExpressionCodegen extends JetVisitor implem } } + @Nullable + private static JetSuperExpression getSuperCallExpression(Call call) { + ReceiverValue explicitReceiver = call.getExplicitReceiver(); + if (explicitReceiver instanceof ExpressionReceiver) { + JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression(); + if (receiverExpression instanceof JetSuperExpression) { + return (JetSuperExpression) receiverExpression; + } + } + return null; + } + + private static boolean isSuperCall(Call call) { + return getSuperCallExpression(call) != null; + } + + // Find the first parent of the current context which corresponds to a subclass of a given class + private CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor) { + CodegenContext c = context; + while (true) { + if ((c instanceof ClassContext || c instanceof AnonymousClassContext) && + DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) { + return c; + } + c = c.getParentContext(); + assert c != null; + } + } + private StackValue returnValueAsStackValue(FunctionDescriptor fd, Type callReturnType) { if (callReturnType != Type.VOID_TYPE) { JetType type = fd.getReturnType(); @@ -2200,7 +2208,9 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitDotQualifiedExpression(JetDotQualifiedExpression expression, StackValue receiver) { - return genQualified(StackValue.none(), expression.getSelectorExpression()); + JetExpression receiverExpression = expression.getReceiverExpression(); + StackValue receiverValue = receiverExpression instanceof JetSuperExpression ? gen(receiverExpression) : StackValue.none(); + return genQualified(receiverValue, expression.getSelectorExpression()); } @Override diff --git a/compiler/testData/codegen/super/innerClassLabeledSuper.kt b/compiler/testData/codegen/super/innerClassLabeledSuper.kt new file mode 100644 index 00000000000..472baa7c6b3 --- /dev/null +++ b/compiler/testData/codegen/super/innerClassLabeledSuper.kt @@ -0,0 +1,38 @@ +trait BK { + fun foo(): String + fun bar(): String +} + +trait K : BK { + override fun foo() = bar() +} + +class A : K { + override fun foo() = "A.foo" + override fun bar() = "A.bar" + + class B : K { + override fun foo() = "B.foo" + override fun bar() = "B.bar" + + fun test1() = super@A.foo() + fun test2() = super@B.foo() + fun test3() = super.foo() + fun test4() = super@A.foo() + fun test5() = super@B.foo() + fun test6() = super.foo() + } +} + + +fun box(): String { + val b = A().B() + if (b.test1() != "A.bar") return "test1 ${b.test1()}" + if (b.test2() != "B.bar") return "test2 ${b.test2()}" + if (b.test3() != "B.bar") return "test3 ${b.test3()}" + if (b.test4() != "A.bar") return "test4 ${b.test4()}" + if (b.test5() != "B.bar") return "test5 ${b.test5()}" + if (b.test6() != "B.bar") return "test6 ${b.test6()}" + + return "OK" +} diff --git a/compiler/testData/codegen/super/innerClassLabeledSuperProperty.kt b/compiler/testData/codegen/super/innerClassLabeledSuperProperty.kt new file mode 100644 index 00000000000..28a5ffdf5c6 --- /dev/null +++ b/compiler/testData/codegen/super/innerClassLabeledSuperProperty.kt @@ -0,0 +1,38 @@ +trait Base { + val foo: String + fun bar(): String +} + +abstract class K : Base { + override val foo = bar() +} + +class A : K() { + override val foo = "A.foo" + override fun bar() = "A.bar" + + class B : K() { + override val foo = "B.foo" + override fun bar() = "B.bar" + + fun test1() = super@A.foo + fun test2() = super@B.foo + fun test3() = super.foo + fun test4() = super@A.foo + fun test5() = super@B.foo + fun test6() = super.foo + } +} + + +fun box(): String { + val b = A().B() + if (b.test1() != "A.bar") return "test1 ${b.test1()}" + if (b.test2() != "B.bar") return "test2 ${b.test2()}" + if (b.test3() != "B.bar") return "test3 ${b.test3()}" + if (b.test4() != "A.bar") return "test4 ${b.test4()}" + if (b.test5() != "B.bar") return "test5 ${b.test5()}" + if (b.test6() != "B.bar") return "test6 ${b.test6()}" + + return "OK" +} diff --git a/compiler/testData/codegen/super/multipleSuperTraits.kt b/compiler/testData/codegen/super/multipleSuperTraits.kt new file mode 100644 index 00000000000..2312888b2fa --- /dev/null +++ b/compiler/testData/codegen/super/multipleSuperTraits.kt @@ -0,0 +1,13 @@ +trait T1 { + fun foo() = "O" +} + +trait T2 { + fun foo() = "K" +} + +class A : T1, T2 { + override fun foo() = super.foo() + super.foo() +} + +fun box() = A().foo() diff --git a/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java index cba7a3cffcd..27f1f979046 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java @@ -46,6 +46,18 @@ public class SuperGenTest extends CodegenTestCase { // System.out.println(generateToText()); } + public void testInnerClassLabeledSuper() { + blackBoxFile("super/innerClassLabeledSuper.kt"); + } + + public void testInnerClassLabeledSuperProperty() { + blackBoxFile("super/innerClassLabeledSuperProperty.kt"); + } + + public void testMultipleSuperTraits() { + blackBoxFile("super/multipleSuperTraits.kt"); + } + public void testEnclosedFun () { blackBoxFile("/super/enclosedFun.jet"); // System.out.println(generateToText());