diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 502242979d2..cb58d3df761 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2635,8 +2635,14 @@ public class ExpressionCodegen extends KtVisitor impleme throw new UnsupportedOperationException(); } + @NotNull public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) { + return generateThisOrOuter(calleeContainingClass, isSuper, false); + } + + @NotNull + public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper, boolean forceOuter) { boolean isSingleton = calleeContainingClass.getKind().isSingleton(); if (isSingleton) { if (calleeContainingClass.equals(context.getThisDescriptor()) && @@ -2662,10 +2668,12 @@ public class ExpressionCodegen extends KtVisitor impleme return result; } - if (isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { + if (!forceOuter && isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass); } + forceOuter = false; + //for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer if (inStartConstructorContext) { result = cur.getOuterExpression(result, false); @@ -3441,10 +3449,7 @@ public class ExpressionCodegen extends KtVisitor impleme if (dispatchReceiver != null) { Type receiverType = typeMapper.mapType(dispatchReceiver.getType()); ReceiverValue receiver = resolvedCall.getDispatchReceiver(); - boolean callSuper = containingDeclaration.isInner() && - receiver instanceof ClassReceiver && - ((ClassReceiver) receiver).getDeclarationDescriptor().getOriginal() != - containingDeclaration.getOriginal(); + boolean callSuper = containingDeclaration.isInner() && receiver instanceof ClassReceiver; generateReceiverValue(receiver, callSuper).put(receiverType, v); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 9620de6daa3..4accf1afd56 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1435,11 +1435,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { String.format("Non-outer parameter incorrectly mapped to outer for %s: %s vs %s", constructorDescriptor, parameters, superParameters); // Super constructor requires OUTER parameter, but our OUTER instance may be different from what is expected by the super - // constructor. We need to traverse our outer classes from the bottom up, to find the needed class - // TODO: isSuper should be "true" but this makes some tests on inner classes extending outer fail - // See innerExtendsOuter.kt, semantics of inner classes extending their outer should be changed to be as in Java + // constructor. We need to traverse our outer classes from the bottom up, to find the needed class. See innerExtendsOuter.kt ClassDescriptor outerForSuper = (ClassDescriptor) superConstructor.getContainingDeclaration().getContainingDeclaration(); - StackValue outer = codegen.generateThisOrOuter(outerForSuper, false); + StackValue outer = codegen.generateThisOrOuter(outerForSuper, true, true); outer.put(outer.type, codegen.v); superIndex++; } diff --git a/compiler/testData/codegen/box/classes/inner/kt6708.kt b/compiler/testData/codegen/box/classes/inner/kt6708.kt new file mode 100644 index 00000000000..db242e7c0bb --- /dev/null +++ b/compiler/testData/codegen/box/classes/inner/kt6708.kt @@ -0,0 +1,12 @@ +open class A() { + open inner class InnerA +} + +class B : A() { + inner class InnerB : A.InnerA() +} + +fun box(): String { + B().InnerB() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/classes/inner/properSuperLinking.kt b/compiler/testData/codegen/box/classes/inner/properSuperLinking.kt new file mode 100644 index 00000000000..230ad1d9ee4 --- /dev/null +++ b/compiler/testData/codegen/box/classes/inner/properSuperLinking.kt @@ -0,0 +1,16 @@ + +open class A(val s: String) { + + val z = s + + fun test() = s + + open inner class B(s: String): A(s) { + fun testB() = z + test() + } +} + +fun box(): String { + val res = A("Fail").B("OK").testB() + return if (res == "OKOK") "OK" else res; +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt b/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt index e90ccb30a21..4b1d51c5ca8 100644 --- a/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt +++ b/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt @@ -1,7 +1,6 @@ // When inner class extends its outer, there are two instances of the outer present in the inner: // the enclosing one and the one in the super call. // Here we test that symbols are resolved to the instance created via the super call. -// This differs from Java, so this test may change when we revisit code generation of inner classes open class Outer(vararg val chars: Char) { open inner class Inner(val s: String): Outer(s[0], s[1]) { diff --git a/compiler/testData/codegen/boxWithJava/innerClass/JavaClass.java b/compiler/testData/codegen/boxWithJava/innerClass/JavaClass.java new file mode 100644 index 00000000000..a5b6cbb06ce --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/innerClass/JavaClass.java @@ -0,0 +1,7 @@ +public abstract class JavaClass { + public abstract InnerClass onCreateInner(); + + public class InnerClass { + + } +} diff --git a/compiler/testData/codegen/boxWithJava/innerClass/Kotlin.kt b/compiler/testData/codegen/boxWithJava/innerClass/Kotlin.kt new file mode 100644 index 00000000000..125d6417f6b --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/innerClass/Kotlin.kt @@ -0,0 +1,9 @@ +public class MyWallpaperService : JavaClass() { + override fun onCreateInner(): JavaClass.InnerClass = MyEngine() + + private inner class MyEngine : JavaClass.InnerClass() +} + +fun box(): String { + return if (MyWallpaperService().onCreateInner() != null) return "OK" else "fail" +} \ 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 262cf259939..c414ace497d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1710,11 +1710,23 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt6708.kt") + public void testKt6708() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/kt6708.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("properSuperLinking.kt") + public void testProperSuperLinking() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/properSuperLinking.kt"); + doTest(fileName); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 41837f1bd6c..5955b5f9627 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -71,6 +71,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("innerClass") + public void testInnerClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/innerClass/"); + doTestWithJava(fileName); + } + @TestMetadata("interfaceCompanion") public void testInterfaceCompanion() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/interfaceCompanion/");