Fix determining enclosing class for closure
Enclosing class for closure is a class whose instance is captured by
closure as an outer 'this', and stored in a field 'this$0'.
Usually enclosing class for closure is an immediate outer class,
including classes for nested closures. For example:
class C {
fun foo() {}
val example1 = L1@ { foo() }
// Enclosing class for lambda 'L1' is 'C'
val example2 = L2a@ { L2b@ { foo() } }
// Enclosing class for nested lambda 'L2b'
// is a closure class for outer lambda 'L2a'
}
However, if the closure is created in a super type constructor call for
the outer class, corresponding instance is considered "uninitialized",
and can't be used as a proper class instance, and can't be referenced:
corresponding code is rejected by front-end.
class Outer {
fun foo() {}
inner class Inner : Base(L3@ { foo() })
// Enclosing class for lambda 'L3' is 'Outer',
// because 'Inner' is uninitialized in super type constructor call.
}
In CodegenAnnotatingVisitor, we maintain a stack of currently
uninitialized classes, and chose enclosing class for closure
as an inner-most surrounding class with initialized instance.
When generating code for this or outer class instance, we skip
contexts corresponding to classes with uninitialized instances.
This fixes a number of bytecode verification errors caused by incorrect
enclosing class for closure.
#KT-4174 Fixed Target versions 1.2.20
#KT-13454 Fixed Target versions 1.2.20
#KT-14148 Fixed Target versions 1.2.20
This commit is contained in:
@@ -4019,6 +4019,111 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class CapturingOuterClassInstanceInSuperCall extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInCapturingOuterClassInstanceInSuperCall() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("kt13454.kt")
|
||||
public void testKt13454() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/kt13454.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt14148.kt")
|
||||
public void testKt14148() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/kt14148.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt4174.kt")
|
||||
public void testKt4174() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/kt4174.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt4174a.kt")
|
||||
public void testKt4174a() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/kt4174a.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedAsImplicitThisInBoundReference.kt")
|
||||
public void testOuterCapturedAsImplicitThisInBoundReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedAsImplicitThisInBoundReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInFunctionLiteral.kt")
|
||||
public void testOuterCapturedInFunctionLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInFunctionLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInInlineLambda.kt")
|
||||
public void testOuterCapturedInInlineLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInInlineLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInLambda.kt")
|
||||
public void testOuterCapturedInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInLambda2.kt")
|
||||
public void testOuterCapturedInLambda2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInLambda2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInLambdaInSecondaryConstructor.kt")
|
||||
public void testOuterCapturedInLambdaInSecondaryConstructor() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInLambdaInSecondaryConstructor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInLocalClass.kt")
|
||||
public void testOuterCapturedInLocalClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInLocalClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInNestedLambda.kt")
|
||||
public void testOuterCapturedInNestedLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInNestedLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInNestedObject.kt")
|
||||
public void testOuterCapturedInNestedObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInNestedObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInObject.kt")
|
||||
public void testOuterCapturedInObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerCapturedInObject2.kt")
|
||||
public void testOuterCapturedInObject2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerCapturedInObject2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outerEnumEntryCapturedInLambdaInInnerClass.kt")
|
||||
public void testOuterEnumEntryCapturedInLambdaInInnerClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturingOuterClassInstanceInSuperCall/outerEnumEntryCapturedInLambdaInInnerClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/closures/closureInsideClosure")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user