IR: fix capturing of type parameters in local functions
collectPotentiallyCapturedTypeParameters no longer stops on the first class when going through parents. This is needed because otherwise type parameters of the containing class, and its outer classes, were never considered "captured", and thus not duplicated/remapped later in LocalDeclarationsLowering. This led to the IR where a local function referenced generic type parameters of the outer class. On JVM, local function is generated into a private static function in that container class, and static functions can't use generic type parameters, which crashed some bytecode processing tools. Also, add another explicit call to `seeType` to cover references to generic type parameters in function return types. #KT-45941 Fixed
This commit is contained in:
+10
-12
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.isLocal
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
@@ -160,6 +159,7 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) {
|
||||
this.valueParameters.forEach { closureBuilder.declareVariable(it) }
|
||||
closureBuilder.declareVariable(this.dispatchReceiverParameter)
|
||||
closureBuilder.declareVariable(this.extensionReceiverParameter)
|
||||
closureBuilder.seeType(this.returnType)
|
||||
|
||||
if (this is IrConstructor) {
|
||||
val constructedClass = (this.parent as IrClass)
|
||||
@@ -174,20 +174,18 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) {
|
||||
}
|
||||
|
||||
private fun collectPotentiallyCapturedTypeParameters(closureBuilder: ClosureBuilder) {
|
||||
var current = closureBuilder.owner.parentClosureBuilder
|
||||
while (current != null) {
|
||||
val container = current.owner
|
||||
|
||||
fun ClosureBuilder.doCollect() {
|
||||
if (owner !is IrClass) {
|
||||
(owner as? IrTypeParametersContainer)?.let { container ->
|
||||
for (tp in container.typeParameters) {
|
||||
closureBuilder.addPotentiallyCapturedTypeParameter(tp)
|
||||
}
|
||||
if (container is IrTypeParametersContainer) {
|
||||
for (typeParameter in container.typeParameters) {
|
||||
closureBuilder.addPotentiallyCapturedTypeParameter(typeParameter)
|
||||
}
|
||||
|
||||
owner.parentClosureBuilder?.doCollect()
|
||||
}
|
||||
}
|
||||
|
||||
closureBuilder.owner.parentClosureBuilder?.doCollect()
|
||||
current = container.parentClosureBuilder
|
||||
}
|
||||
}
|
||||
|
||||
private val IrDeclaration.parentClosureBuilder: ClosureBuilder?
|
||||
@@ -205,7 +203,7 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) {
|
||||
else -> null
|
||||
}
|
||||
|
||||
private inner class ClosureCollectorVisitor() : IrElementVisitor<Unit, ClosureBuilder?> {
|
||||
private inner class ClosureCollectorVisitor : IrElementVisitor<Unit, ClosureBuilder?> {
|
||||
|
||||
override fun visitElement(element: IrElement, data: ClosureBuilder?) {
|
||||
element.acceptChildren(this, data)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_SIGNATURES
|
||||
|
||||
class A<T>(val result: T) {
|
||||
fun f(): T {
|
||||
fun g(): T = result
|
||||
return g()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<TT;>;> A$f$1 {
|
||||
// source: 'genericClass.kt'
|
||||
public final <()TT;> method invoke(): java.lang.Object
|
||||
<null> method <init>(p0: A): void
|
||||
enclosing method A.f()Ljava/lang/Object;
|
||||
synthetic final field <null> this$0: A
|
||||
inner (anonymous) class A$f$1
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<<T:Ljava/lang/Object;>Ljava/lang/Object;> A {
|
||||
// source: 'genericClass.kt'
|
||||
public final <()TT;> method f(): java.lang.Object
|
||||
public final <()TT;> method getResult(): java.lang.Object
|
||||
public <(TT;)V> method <init>(p0: java.lang.Object): void
|
||||
private final field <TT;> result: java.lang.Object
|
||||
inner (anonymous) class A$f$1
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@kotlin.Metadata
|
||||
public final class<<T:Ljava/lang/Object;>Ljava/lang/Object;> A {
|
||||
// source: 'genericClass.kt'
|
||||
public final <()TT;> method f(): java.lang.Object
|
||||
public final <()TT;> method getResult(): java.lang.Object
|
||||
public <(TT;)V> method <init>(p0: java.lang.Object): void
|
||||
private final static <<T:Ljava/lang/Object;>(LA<TT;>;)TT;> method f$g(p0: A): java.lang.Object
|
||||
private final field <TT;> result: java.lang.Object
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// WITH_SIGNATURES
|
||||
|
||||
class A<T>(val result: T) {
|
||||
inner class B {
|
||||
inner class C {
|
||||
fun f() {
|
||||
fun g(t: T) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function1<TT;Lkotlin/Unit;>;> A$B$C$f$1 {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public final <(TT;)V> method invoke(p0: java.lang.Object): void
|
||||
static <null> method <clinit>(): void
|
||||
<null> method <init>(): void
|
||||
public synthetic bridge <null> method invoke(p0: java.lang.Object): java.lang.Object
|
||||
enclosing method A$B$C.f()V
|
||||
public final static field <null> INSTANCE: A$B$C$f$1
|
||||
inner (anonymous) class A$B$C$f$1
|
||||
public final inner class A$B
|
||||
public final inner class A$B$C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> A$B$C {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public <()V> method <init>(p0: A$B): void
|
||||
public final <null> method f(): void
|
||||
synthetic final field <null> this$0: A$B
|
||||
inner (anonymous) class A$B$C$f$1
|
||||
public final inner class A$B
|
||||
public final inner class A$B$C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> A$B {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public <()V> method <init>(p0: A): void
|
||||
synthetic final field <null> this$0: A
|
||||
public final inner class A$B
|
||||
public final inner class A$B$C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<<T:Ljava/lang/Object;>Ljava/lang/Object;> A {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public final <()TT;> method getResult(): java.lang.Object
|
||||
public <(TT;)V> method <init>(p0: java.lang.Object): void
|
||||
private final field <TT;> result: java.lang.Object
|
||||
public final inner class A$B
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
@kotlin.Metadata
|
||||
public final class<null> A$B$C {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public <()V> method <init>(p0: A$B): void
|
||||
private final static <<T:Ljava/lang/Object;>(TT;)V> method f$g(p0: java.lang.Object): void
|
||||
public final <null> method f(): void
|
||||
synthetic final field <LA<TT;>.B;> this$0: A$B
|
||||
public final inner class A$B
|
||||
public final inner class A$B$C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> A$B {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public <()V> method <init>(p0: A): void
|
||||
synthetic final field <LA<TT;>;> this$0: A
|
||||
public final inner class A$B
|
||||
public final inner class A$B$C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<<T:Ljava/lang/Object;>Ljava/lang/Object;> A {
|
||||
// source: 'genericInnerClass.kt'
|
||||
public final <()TT;> method getResult(): java.lang.Object
|
||||
public <(TT;)V> method <init>(p0: java.lang.Object): void
|
||||
private final field <TT;> result: java.lang.Object
|
||||
public final inner class A$B
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// WITH_SIGNATURES
|
||||
|
||||
class A<T>(val result: T) {
|
||||
fun b() {
|
||||
class C<S> {
|
||||
fun f() {
|
||||
fun g(t: T): S? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function1<TT;TS;>;> A$b$C$f$1 {
|
||||
// source: 'genericLocalClass.kt'
|
||||
public final @org.jetbrains.annotations.Nullable <(TT;)TS;> method invoke(p0: java.lang.Object): java.lang.Object
|
||||
static <null> method <clinit>(): void
|
||||
<null> method <init>(): void
|
||||
enclosing method A$b$C.f()V
|
||||
public final static field <null> INSTANCE: A$b$C$f$1
|
||||
inner (anonymous) class A$b$C$f$1
|
||||
inner (local) class A$b$C C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<<S:Ljava/lang/Object;>Ljava/lang/Object;> A$b$C {
|
||||
// source: 'genericLocalClass.kt'
|
||||
public <null> method <init>(): void
|
||||
public final <null> method f(): void
|
||||
enclosing method A.b()V
|
||||
inner (anonymous) class A$b$C$f$1
|
||||
inner (local) class A$b$C C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<<T:Ljava/lang/Object;>Ljava/lang/Object;> A {
|
||||
// source: 'genericLocalClass.kt'
|
||||
public final <()TT;> method getResult(): java.lang.Object
|
||||
public <(TT;)V> method <init>(p0: java.lang.Object): void
|
||||
public final <null> method b(): void
|
||||
private final field <TT;> result: java.lang.Object
|
||||
inner (local) class A$b$C C
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
@kotlin.Metadata
|
||||
public final class<<S:Ljava/lang/Object;>Ljava/lang/Object;> A$b$C {
|
||||
// source: 'genericLocalClass.kt'
|
||||
private final static <<T:Ljava/lang/Object;S:Ljava/lang/Object;>(TT;)TS;> method f$g(p0: java.lang.Object): java.lang.Object
|
||||
public <null> method <init>(): void
|
||||
public final <null> method f(): void
|
||||
enclosing method A.b()V
|
||||
inner (local) class A$b$C C
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<<T:Ljava/lang/Object;>Ljava/lang/Object;> A {
|
||||
// source: 'genericLocalClass.kt'
|
||||
public final <()TT;> method getResult(): java.lang.Object
|
||||
public <(TT;)V> method <init>(p0: java.lang.Object): void
|
||||
public final <null> method b(): void
|
||||
private final field <TT;> result: java.lang.Object
|
||||
inner (local) class A$b$C C
|
||||
}
|
||||
+18
@@ -1748,6 +1748,24 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericClass.kt")
|
||||
public void testGenericClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericInnerClass.kt")
|
||||
public void testGenericInnerClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericLocalClass.kt")
|
||||
public void testGenericLocalClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inInitBlock.kt")
|
||||
public void testInInitBlock() throws Exception {
|
||||
|
||||
+18
@@ -1748,6 +1748,24 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericClass.kt")
|
||||
public void testGenericClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericInnerClass.kt")
|
||||
public void testGenericInnerClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericLocalClass.kt")
|
||||
public void testGenericLocalClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inInitBlock.kt")
|
||||
public void testInInitBlock() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user