From 65b85711e3b441370be8f8567f850dfa55f01cf3 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Fri, 30 Oct 2015 16:48:51 +0300 Subject: [PATCH] Fix for KT-3335: Creating imported super class' inner class fails in codegen #KT-3335 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 14 +++++-- .../jetbrains/kotlin/codegen/StackValue.java | 4 +- .../box/classes/inner/instantiateInDerived.kt | 40 ++++++++++++++++++ .../inner/instantiateInDerivedLabeled.kt | 42 +++++++++++++++++++ .../classes/inner/instantiateInSameClass.kt | 34 +++++++++++++++ .../codegen/box/classes/inner/properOuter.kt | 16 +++++++ .../BlackBoxCodegenTestGenerated.java | 33 +++++++++++++++ 7 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/box/classes/inner/instantiateInDerived.kt create mode 100644 compiler/testData/codegen/box/classes/inner/instantiateInDerivedLabeled.kt create mode 100644 compiler/testData/codegen/box/classes/inner/instantiateInSameClass.kt create mode 100644 compiler/testData/codegen/box/classes/inner/properOuter.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index ce5dd2e4c2f..502242979d2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2562,7 +2562,7 @@ public class ExpressionCodegen extends KtVisitor impleme } @NotNull - public StackValue generateReceiverValue(@NotNull ReceiverValue receiverValue) { + public StackValue generateReceiverValue(@NotNull ReceiverValue receiverValue, boolean isSuper) { if (receiverValue instanceof ClassReceiver) { ClassDescriptor receiverDescriptor = ((ClassReceiver) receiverValue).getDeclarationDescriptor(); if (DescriptorUtils.isCompanionObject(receiverDescriptor)) { @@ -2575,7 +2575,7 @@ public class ExpressionCodegen extends KtVisitor impleme } } else { - return StackValue.thisOrOuter(this, receiverDescriptor, false, isEnumEntry(receiverDescriptor)); + return StackValue.thisOrOuter(this, receiverDescriptor, isSuper, isEnumEntry(receiverDescriptor)); } } else if (receiverValue instanceof ScriptReceiver) { @@ -3437,14 +3437,20 @@ public class ExpressionCodegen extends KtVisitor impleme ConstructorDescriptor constructor = getConstructorDescriptor(resolvedCall); ReceiverParameterDescriptor dispatchReceiver = constructor.getDispatchReceiverParameter(); + ClassDescriptor containingDeclaration = constructor.getContainingDeclaration(); if (dispatchReceiver != null) { Type receiverType = typeMapper.mapType(dispatchReceiver.getType()); - generateReceiverValue(resolvedCall.getDispatchReceiver()).put(receiverType, v); + ReceiverValue receiver = resolvedCall.getDispatchReceiver(); + boolean callSuper = containingDeclaration.isInner() && + receiver instanceof ClassReceiver && + ((ClassReceiver) receiver).getDeclarationDescriptor().getOriginal() != + containingDeclaration.getOriginal(); + generateReceiverValue(receiver, callSuper).put(receiverType, v); } // Resolved call to local class constructor doesn't have dispatchReceiver, so we need to generate closure on stack // See StackValue.receiver for more info - pushClosureOnStack(constructor.getContainingDeclaration(), dispatchReceiver == null, defaultCallGenerator); + pushClosureOnStack(containingDeclaration, dispatchReceiver == null, defaultCallGenerator); constructor = SamCodegenUtil.resolveSamAdapter(constructor); CallableMethod method = typeMapper.mapToCallableMethod(constructor, false); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index c06d7d96fbc..5be1045765f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -535,7 +535,7 @@ public abstract class StackValue { ) { if (receiver == none()) { if (receiverValue.exists()) { - return codegen.generateReceiverValue(receiverValue); + return codegen.generateReceiverValue(receiverValue, false); } else if (isLocalFunCall(callableMethod) && !isExtension) { StackValue value = codegen.findLocalOrCapturedValue(resolvedCall.getResultingDescriptor().getOriginal()); @@ -862,7 +862,7 @@ public abstract class StackValue { if (resolvedSetCall.getDispatchReceiver().exists()) { if (resolvedSetCall.getExtensionReceiver().exists()) { - codegen.generateReceiverValue(resolvedSetCall.getDispatchReceiver()).put(OBJECT_TYPE, v); + codegen.generateReceiverValue(resolvedSetCall.getDispatchReceiver(), false).put(OBJECT_TYPE, v); } v.load(realReceiverIndex, realReceiverType); } diff --git a/compiler/testData/codegen/box/classes/inner/instantiateInDerived.kt b/compiler/testData/codegen/box/classes/inner/instantiateInDerived.kt new file mode 100644 index 00000000000..2f928428baf --- /dev/null +++ b/compiler/testData/codegen/box/classes/inner/instantiateInDerived.kt @@ -0,0 +1,40 @@ +open class A(val value: String) { + inner class B(val s: String) { + val result = value + "_" + s + } +} + +class C : A("fromC") { + fun classReceiver() = B("OK") + fun superReceiver() = super.B("OK") + + fun newAReceiver() = A("fromA").B("OK") + fun aReceiver(): B { + val a = A("fromA") + return a.B("OK") + } + + fun A.extReceiver() = this.B("OK") + fun extReceiver() = A("fromA").extReceiver() +} + +fun box(): String { + val receiver = C() + var result = receiver.classReceiver().result + if (result != "fromC_OK") return "fail 1: $result" + + result = receiver.superReceiver().result + if (result != "fromC_OK") return "fail 2: $result" + + + result = receiver.aReceiver().result + if (result != "fromA_OK") return "fail 3: $result" + + result = receiver.newAReceiver().result + if (result != "fromA_OK") return "fail 3: $result" + + result = receiver.extReceiver().result + if (result != "fromA_OK") return "fail 3: $result" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/classes/inner/instantiateInDerivedLabeled.kt b/compiler/testData/codegen/box/classes/inner/instantiateInDerivedLabeled.kt new file mode 100644 index 00000000000..34db2545d47 --- /dev/null +++ b/compiler/testData/codegen/box/classes/inner/instantiateInDerivedLabeled.kt @@ -0,0 +1,42 @@ +open class A(val value: String) { + inner class B(val s: String) { + val result = value + "_" + s + } +} + +class C : A("fromC") { + + inner class X: A("fromX") { + fun classReceiver() = B("OK") + fun superReceiver() = super.B("OK") + fun superXReceiver() = super@X.B("OK") + fun superXCastReceiver() = (this@X as A).B("OK") + + fun superCReceiver() = super@C.B("OK") + fun superCCastReceiver() = (this@C as A).B("OK") + } +} + +fun box(): String { + val receiver = C().X() + var result = receiver.classReceiver().result + if (result != "fromX_OK") return "fail 1: $result" + + result = receiver.superReceiver().result + if (result != "fromX_OK") return "fail 2: $result" + + result = receiver.superXReceiver().result + if (result != "fromX_OK") return "fail 3: $result" + + result = receiver.superXCastReceiver().result + if (result != "fromX_OK") return "fail 4: $result" + + + result = receiver.superCReceiver().result + if (result != "fromC_OK") return "fail 3: $result" + + result = receiver.superCCastReceiver().result + if (result != "fromC_OK") return "fail 4: $result" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/classes/inner/instantiateInSameClass.kt b/compiler/testData/codegen/box/classes/inner/instantiateInSameClass.kt new file mode 100644 index 00000000000..bc6200c60c5 --- /dev/null +++ b/compiler/testData/codegen/box/classes/inner/instantiateInSameClass.kt @@ -0,0 +1,34 @@ +class C(val value: String = "C") { + + inner class B(val s: String) { + val result = value + "_" + s + } + + fun classReceiver() = B("OK") + + fun newCReceiver() = C("newC").B("OK") + fun cReceiver(): B { + val c = C("newC") + return c.B("OK") + } + + fun C.extReceiver1() = this.B("OK") + fun extReceiver() = C("newC").extReceiver1() +} + +fun box(): String { + val receiver = C() + var result = receiver.classReceiver().result + if (result != "C_OK") return "fail 1: $result" + + result = receiver.cReceiver().result + if (result != "newC_OK") return "fail 3: $result" + + result = receiver.newCReceiver().result + if (result != "newC_OK") return "fail 3: $result" + + result = receiver.extReceiver().result + if (result != "newC_OK") return "fail 3: $result" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/classes/inner/properOuter.kt b/compiler/testData/codegen/box/classes/inner/properOuter.kt new file mode 100644 index 00000000000..41d1e4406db --- /dev/null +++ b/compiler/testData/codegen/box/classes/inner/properOuter.kt @@ -0,0 +1,16 @@ + +open class A(val s: String) { + open inner class B(val s: String) { + fun testB() = s + this@A.s + } + + open inner class C(): A("C") { + fun testC() = + B("B_").testB() + } +} + +fun box(): String { + val res = A("A").C().testC() + return if (res == "B_C") "OK" else res; +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index e388bccfcfe..262cf259939 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1683,6 +1683,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/typedDelegation.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/classes/inner") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Inner extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInInner() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classes/inner"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("instantiateInDerived.kt") + public void testInstantiateInDerived() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/instantiateInDerived.kt"); + doTest(fileName); + } + + @TestMetadata("instantiateInDerivedLabeled.kt") + public void testInstantiateInDerivedLabeled() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/instantiateInDerivedLabeled.kt"); + doTest(fileName); + } + + @TestMetadata("instantiateInSameClass.kt") + public void testInstantiateInSameClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/instantiateInSameClass.kt"); + doTest(fileName); + } + + @TestMetadata("properOuter.kt") + public void testProperOuter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/properOuter.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/closures")