Fix for KT-7421: Unable to inherit from inner class

Fix for KT-6708: Compiler Error when extending open inner class: "java.lang.RuntimeException: Error generating primary constructor of class InnerB with kind IMPLEMENTATION"

  #KT-7421 Fixed
  #KT-6708 Fixed
This commit is contained in:
Michael Bogdanov
2015-10-30 16:49:38 +03:00
parent 65b85711e3
commit 15eaa15b65
9 changed files with 74 additions and 10 deletions
@@ -2635,8 +2635,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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);
}
@@ -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++;
}
+12
View File
@@ -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"
}
@@ -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;
}
@@ -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]) {
@@ -0,0 +1,7 @@
public abstract class JavaClass {
public abstract InnerClass onCreateInner();
public class InnerClass {
}
}
@@ -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"
}
@@ -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);
}
}
}
@@ -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/");