diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt index 970636aebff..a1fe49f3f45 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt @@ -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 { + private inner class ClosureCollectorVisitor : IrElementVisitor { override fun visitElement(element: IrElement, data: ClosureBuilder?) { element.acceptChildren(this, data) diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.kt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.kt new file mode 100644 index 00000000000..7c0e1ee01e1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.kt @@ -0,0 +1,8 @@ +// WITH_SIGNATURES + +class A(val result: T) { + fun f(): T { + fun g(): T = result + return g() + } +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.txt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.txt new file mode 100644 index 00000000000..9d7b409e32c --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass.txt @@ -0,0 +1,19 @@ +@kotlin.Metadata +final class;> A$f$1 { + // source: 'genericClass.kt' + public final <()TT;> method invoke(): java.lang.Object + method (p0: A): void + enclosing method A.f()Ljava/lang/Object; + synthetic final field this$0: A + inner (anonymous) class A$f$1 +} + +@kotlin.Metadata +public final class<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 (p0: java.lang.Object): void + private final field result: java.lang.Object + inner (anonymous) class A$f$1 +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass_ir.txt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass_ir.txt new file mode 100644 index 00000000000..2e5c93c383e --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericClass_ir.txt @@ -0,0 +1,9 @@ +@kotlin.Metadata +public final class<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 (p0: java.lang.Object): void + private final static <(LA;)TT;> method f$g(p0: A): java.lang.Object + private final field result: java.lang.Object +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.kt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.kt new file mode 100644 index 00000000000..04c41f1146c --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.kt @@ -0,0 +1,11 @@ +// WITH_SIGNATURES + +class A(val result: T) { + inner class B { + inner class C { + fun f() { + fun g(t: T) {} + } + } + } +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.txt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.txt new file mode 100644 index 00000000000..49ca6af06eb --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass.txt @@ -0,0 +1,42 @@ +@kotlin.Metadata +final class;> A$B$C$f$1 { + // source: 'genericInnerClass.kt' + public final <(TT;)V> method invoke(p0: java.lang.Object): void + static method (): void + method (): void + public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object + enclosing method A$B$C.f()V + public final static field 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 A$B$C { + // source: 'genericInnerClass.kt' + public <()V> method (p0: A$B): void + public final method f(): void + synthetic final field 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 A$B { + // source: 'genericInnerClass.kt' + public <()V> method (p0: A): void + synthetic final field this$0: A + public final inner class A$B + public final inner class A$B$C +} + +@kotlin.Metadata +public final class<Ljava/lang/Object;> A { + // source: 'genericInnerClass.kt' + public final <()TT;> method getResult(): java.lang.Object + public <(TT;)V> method (p0: java.lang.Object): void + private final field result: java.lang.Object + public final inner class A$B +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass_ir.txt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass_ir.txt new file mode 100644 index 00000000000..9e9879326fc --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericInnerClass_ir.txt @@ -0,0 +1,28 @@ +@kotlin.Metadata +public final class A$B$C { + // source: 'genericInnerClass.kt' + public <()V> method (p0: A$B): void + private final static <(TT;)V> method f$g(p0: java.lang.Object): void + public final method f(): void + synthetic final field .B;> this$0: A$B + public final inner class A$B + public final inner class A$B$C +} + +@kotlin.Metadata +public final class A$B { + // source: 'genericInnerClass.kt' + public <()V> method (p0: A): void + synthetic final field ;> this$0: A + public final inner class A$B + public final inner class A$B$C +} + +@kotlin.Metadata +public final class<Ljava/lang/Object;> A { + // source: 'genericInnerClass.kt' + public final <()TT;> method getResult(): java.lang.Object + public <(TT;)V> method (p0: java.lang.Object): void + private final field result: java.lang.Object + public final inner class A$B +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.kt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.kt new file mode 100644 index 00000000000..55f576315f9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.kt @@ -0,0 +1,11 @@ +// WITH_SIGNATURES + +class A(val result: T) { + fun b() { + class C { + fun f() { + fun g(t: T): S? = null + } + } + } +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.txt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.txt new file mode 100644 index 00000000000..3b701acd253 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass.txt @@ -0,0 +1,31 @@ +@kotlin.Metadata +final class;> 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 method (): void + method (): void + enclosing method A$b$C.f()V + public final static field 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<Ljava/lang/Object;> A$b$C { + // source: 'genericLocalClass.kt' + public method (): void + public final 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<Ljava/lang/Object;> A { + // source: 'genericLocalClass.kt' + public final <()TT;> method getResult(): java.lang.Object + public <(TT;)V> method (p0: java.lang.Object): void + public final method b(): void + private final field result: java.lang.Object + inner (local) class A$b$C C +} diff --git a/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass_ir.txt b/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass_ir.txt new file mode 100644 index 00000000000..7c636919729 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/localFunctions/genericLocalClass_ir.txt @@ -0,0 +1,19 @@ +@kotlin.Metadata +public final class<Ljava/lang/Object;> A$b$C { + // source: 'genericLocalClass.kt' + private final static <(TT;)TS;> method f$g(p0: java.lang.Object): java.lang.Object + public method (): void + public final method f(): void + enclosing method A.b()V + inner (local) class A$b$C C +} + +@kotlin.Metadata +public final class<Ljava/lang/Object;> A { + // source: 'genericLocalClass.kt' + public final <()TT;> method getResult(): java.lang.Object + public <(TT;)V> method (p0: java.lang.Object): void + public final method b(): void + private final field result: java.lang.Object + inner (local) class A$b$C C +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java index c73e14d2c1f..85c45654fd1 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java @@ -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 { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java index 707485cef97..9c20466bc01 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java @@ -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 {