diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperClasses.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperClasses.kt index 6bc5946ac4a..c019140200b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperClasses.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperClasses.kt @@ -38,8 +38,7 @@ class SamWrapperClasses(private val state: GenerationState) { contextDescriptor: CallableMemberDescriptor ): Type { val parentContext = expressionCodegen.context - val isInsideInline = InlineUtil.isInlineOrContainingInline(parentContext.contextDescriptor) || - isInsideInlineLambdaContext(parentContext, state) + val isInsideInline = InlineUtil.isInPublicInlineScope(parentContext.contextDescriptor) return samInterfaceToWrapperClass.getOrPut(WrapperKey(samType, file, isInsideInline)) { SamWrapperCodegen(state, samType, expressionCodegen.parentCodegen, parentContext, isInsideInline) .genWrapper(file, contextDescriptor) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index e7cac802815..f34c2e4d8ab 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -224,7 +224,7 @@ internal fun isSamWrapperConstructorCall(internalName: String, methodName: Strin isConstructor(methodName) && isSamWrapper(internalName) internal fun isAnonymousClass(internalName: String) = - !isSamWrapper(internalName) && + !internalName.contains("\$sam\$") && internalName.substringAfterLast('/').substringAfterLast("$", "").isInteger() fun wrapWithMaxLocalCalc(methodNode: MethodNode) = diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index c6e588d76ad..1ca90a46f4f 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -4996,6 +4996,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt"); } + @Test + @TestMetadata("samWrapperInInlineLambda2.kt") + public void testSamWrapperInInlineLambda2() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt"); + } + @Test @TestMetadata("samWrapperOfLambda.kt") public void testSamWrapperOfLambda() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt index 4266d0ac37f..7ff377c5757 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt @@ -10,12 +10,14 @@ import org.jetbrains.kotlin.backend.common.lower.SingleAbstractMethodLowering import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound +import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope import org.jetbrains.kotlin.backend.jvm.ir.rawType import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall @@ -31,14 +33,8 @@ internal val singleAbstractMethodPhase = makeIrFilePhase( ) private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : SingleAbstractMethodLowering(context) { - // The JVM BE produces inline SAM wrappers both in the scope of an inline function as well as in the scope - // of an inline lambda. Compare with `SamWrapperClasses.getSamWrapperClass`. override val inInlineFunctionScope: Boolean - get() = allScopes.any { scope -> - scope.irElement.safeAs()?.let { - it.isInline || it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA - } ?: false - } + get() = allScopes.any { it.irElement.safeAs()?.isInPublicInlineScope == true } override fun getWrapperVisibility(expression: IrTypeOperatorCall, scopes: List) = if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY diff --git a/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt b/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt new file mode 100644 index 00000000000..f9c654c316f --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt @@ -0,0 +1,10 @@ +// KOTLIN_CONFIGURATION_FLAGS: SAM_CONVERSIONS=CLASS +// WITH_SIGNATURES +package test + +// SAM adapters inside of private inline functions don't need to be public, +// since we do not refer to them from other packages. +fun test() { + val lambda = { } + 1.apply { Runnable(lambda) } +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.txt b/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.txt new file mode 100644 index 00000000000..1603b288484 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.txt @@ -0,0 +1,28 @@ +@kotlin.Metadata +synthetic final class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 { + // source: 'privateInlineSamAdapter.kt' + method (p0: kotlin.jvm.functions.Function0): void + public synthetic final method run(): void + enclosing method test/PrivateInlineSamAdapterKt.test()V + private synthetic final field function: kotlin.jvm.functions.Function0 + inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 +} + +@kotlin.Metadata +final class;> test/PrivateInlineSamAdapterKt$test$lambda$1 { + // source: 'privateInlineSamAdapter.kt' + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void + enclosing method test/PrivateInlineSamAdapterKt.test()V + public final static field INSTANCE: test.PrivateInlineSamAdapterKt$test$lambda$1 + inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1 +} + +@kotlin.Metadata +public final class test/PrivateInlineSamAdapterKt { + // source: 'privateInlineSamAdapter.kt' + public final static method test(): void + inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1 +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter_ir.txt new file mode 100644 index 00000000000..c4c88b8bdf9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter_ir.txt @@ -0,0 +1,29 @@ +@kotlin.Metadata +synthetic final class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 { + // source: 'privateInlineSamAdapter.kt' + method (p0: kotlin.jvm.functions.Function0): void + public synthetic final method run(): void + enclosing class test/PrivateInlineSamAdapterKt + private synthetic final field function: kotlin.jvm.functions.Function0 + inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 +} + +@kotlin.Metadata +final class;> test/PrivateInlineSamAdapterKt$test$lambda$1 { + // source: 'privateInlineSamAdapter.kt' + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void + enclosing method test/PrivateInlineSamAdapterKt.test()V + public final static field INSTANCE: test.PrivateInlineSamAdapterKt$test$lambda$1 + inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1 +} + +@kotlin.Metadata +public final class test/PrivateInlineSamAdapterKt { + // source: 'privateInlineSamAdapter.kt' + public final static method test(): void + inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 + inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1 +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt b/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt new file mode 100644 index 00000000000..e76eaaa56bd --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt @@ -0,0 +1,11 @@ +// KOTLIN_CONFIGURATION_FLAGS: SAM_CONVERSIONS=CLASS +// WITH_SIGNATURES +package test + +// We used to generate SAM adapters inside of inline lambdas as +// inline SAM wrappers (`...$sam$i$...`). This is unnecessary, unless +// the code is itself contained in an inline function. +fun test() { + val lambda = { } + 1.apply { Runnable(lambda) } +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.txt b/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.txt new file mode 100644 index 00000000000..14a3f59a29b --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.txt @@ -0,0 +1,28 @@ +@kotlin.Metadata +synthetic final class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 { + // source: 'samAdapterInInlineLambda.kt' + method (p0: kotlin.jvm.functions.Function0): void + public synthetic final method run(): void + enclosing method test/SamAdapterInInlineLambdaKt.test()V + private synthetic final field function: kotlin.jvm.functions.Function0 + inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 +} + +@kotlin.Metadata +final class;> test/SamAdapterInInlineLambdaKt$test$lambda$1 { + // source: 'samAdapterInInlineLambda.kt' + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void + enclosing method test/SamAdapterInInlineLambdaKt.test()V + public final static field INSTANCE: test.SamAdapterInInlineLambdaKt$test$lambda$1 + inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1 +} + +@kotlin.Metadata +public final class test/SamAdapterInInlineLambdaKt { + // source: 'samAdapterInInlineLambda.kt' + public final static method test(): void + inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1 +} diff --git a/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda_ir.txt b/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda_ir.txt new file mode 100644 index 00000000000..c921412e745 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda_ir.txt @@ -0,0 +1,29 @@ +@kotlin.Metadata +synthetic final class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 { + // source: 'samAdapterInInlineLambda.kt' + method (p0: kotlin.jvm.functions.Function0): void + public synthetic final method run(): void + enclosing class test/SamAdapterInInlineLambdaKt + private synthetic final field function: kotlin.jvm.functions.Function0 + inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 +} + +@kotlin.Metadata +final class;> test/SamAdapterInInlineLambdaKt$test$lambda$1 { + // source: 'samAdapterInInlineLambda.kt' + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void + enclosing method test/SamAdapterInInlineLambdaKt.test()V + public final static field INSTANCE: test.SamAdapterInInlineLambdaKt$test$lambda$1 + inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1 +} + +@kotlin.Metadata +public final class test/SamAdapterInInlineLambdaKt { + // source: 'samAdapterInInlineLambda.kt' + public final static method test(): void + inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 + inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1 +} diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt index c3f5e372ea3..c21e6954200 100644 --- a/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt @@ -16,4 +16,5 @@ fun box(): String { return result } -// 1 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0. \(Lkotlin/jvm/functions/Function0;\)V \ No newline at end of file +// 1 INVOKESPECIAL TestKt\$sam\$java_lang_Runnable\$0. \(Lkotlin/jvm/functions/Function0;\)V +// 0 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0. \(Lkotlin/jvm/functions/Function0;\)V \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt new file mode 100644 index 00000000000..eb818294636 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt @@ -0,0 +1,20 @@ +// SAM_CONVERSIONS: CLASS +// FILE: J.java + +public class J { + public static void g(Runnable r) { + r.run(); + } +} + +// FILE: test.kt + +inline fun box(): String { + var result = "Fail" + val setter = { result = "OK" } + 1.apply { J.g(setter) } + return result +} + +// 0 INVOKESPECIAL TestKt\$sam\$java_lang_Runnable\$0. \(Lkotlin/jvm/functions/Function0;\)V +// 1 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0. \(Lkotlin/jvm/functions/Function0;\)V \ No newline at end of file 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 bade89058b3..262dc7a4565 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 @@ -2052,6 +2052,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/sam/nonApproxToValidSupertype2.kt"); } + @Test + @TestMetadata("privateInlineSamAdapter.kt") + public void testPrivateInlineSamAdapter() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt"); + } + @Test @TestMetadata("reusedSamWrapperClasses.kt") public void testReusedSamWrapperClasses() throws Exception { @@ -2064,6 +2070,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterAndInlinedOne.kt"); } + @Test + @TestMetadata("samAdapterInInlineLambda.kt") + public void testSamAdapterInInlineLambda() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt"); + } + @Test @TestMetadata("specializedFunInterface.kt") public void testSpecializedFunInterface() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index 49e87fc7492..98f5ed62474 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -4852,6 +4852,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt"); } + @Test + @TestMetadata("samWrapperInInlineLambda2.kt") + public void testSamWrapperInInlineLambda2() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt"); + } + @Test @TestMetadata("samWrapperOfLambda.kt") public void testSamWrapperOfLambda() 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 36bcf55f67f..605545910be 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 @@ -2100,6 +2100,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/sam/nonApproxToValidSupertype2.kt"); } + @Test + @TestMetadata("privateInlineSamAdapter.kt") + public void testPrivateInlineSamAdapter() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/sam/privateInlineSamAdapter.kt"); + } + @Test @TestMetadata("reusedSamWrapperClasses.kt") public void testReusedSamWrapperClasses() throws Exception { @@ -2112,6 +2118,12 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterAndInlinedOne.kt"); } + @Test + @TestMetadata("samAdapterInInlineLambda.kt") + public void testSamAdapterInInlineLambda() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/sam/samAdapterInInlineLambda.kt"); + } + @Test @TestMetadata("specializedFunInterface.kt") public void testSpecializedFunInterface() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index e20027db1b5..ab03464c687 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -4996,6 +4996,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda.kt"); } + @Test + @TestMetadata("samWrapperInInlineLambda2.kt") + public void testSamWrapperInInlineLambda2() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperInInlineLambda2.kt"); + } + @Test @TestMetadata("samWrapperOfLambda.kt") public void testSamWrapperOfLambda() throws Exception {