JVM: Only produce inline SAM wrappers in public inline scope
This commit is contained in:
committed by
Alexander Udalov
parent
50bbf4f269
commit
c9b0cc5b32
@@ -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)
|
||||
|
||||
@@ -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) =
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+3
-7
@@ -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<IrFunction>()?.let {
|
||||
it.isInline || it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
} ?: false
|
||||
}
|
||||
get() = allScopes.any { it.irElement.safeAs<IrDeclaration>()?.isInPublicInlineScope == true }
|
||||
|
||||
override fun getWrapperVisibility(expression: IrTypeOperatorCall, scopes: List<ScopeWithIr>) =
|
||||
if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class<null> test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 {
|
||||
// source: 'privateInlineSamAdapter.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method run(): void
|
||||
enclosing method test/PrivateInlineSamAdapterKt.test()V
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/PrivateInlineSamAdapterKt$test$lambda$1 {
|
||||
// source: 'privateInlineSamAdapter.kt'
|
||||
static <null> method <clinit>(): void
|
||||
<null> method <init>(): void
|
||||
public synthetic bridge <null> method invoke(): java.lang.Object
|
||||
public final <null> method invoke(): void
|
||||
enclosing method test/PrivateInlineSamAdapterKt.test()V
|
||||
public final static field <null> INSTANCE: test.PrivateInlineSamAdapterKt$test$lambda$1
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> test/PrivateInlineSamAdapterKt {
|
||||
// source: 'privateInlineSamAdapter.kt'
|
||||
public final static <null> method test(): void
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class<null> test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0 {
|
||||
// source: 'privateInlineSamAdapter.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method run(): void
|
||||
enclosing class test/PrivateInlineSamAdapterKt
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/PrivateInlineSamAdapterKt$test$lambda$1 {
|
||||
// source: 'privateInlineSamAdapter.kt'
|
||||
static <null> method <clinit>(): void
|
||||
<null> method <init>(): void
|
||||
public synthetic bridge <null> method invoke(): java.lang.Object
|
||||
public final <null> method invoke(): void
|
||||
enclosing method test/PrivateInlineSamAdapterKt.test()V
|
||||
public final static field <null> INSTANCE: test.PrivateInlineSamAdapterKt$test$lambda$1
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> test/PrivateInlineSamAdapterKt {
|
||||
// source: 'privateInlineSamAdapter.kt'
|
||||
public final static <null> method test(): void
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$sam$java_lang_Runnable$0
|
||||
inner (anonymous) class test/PrivateInlineSamAdapterKt$test$lambda$1
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class<null> test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 {
|
||||
// source: 'samAdapterInInlineLambda.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method run(): void
|
||||
enclosing method test/SamAdapterInInlineLambdaKt.test()V
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/SamAdapterInInlineLambdaKt$test$lambda$1 {
|
||||
// source: 'samAdapterInInlineLambda.kt'
|
||||
static <null> method <clinit>(): void
|
||||
<null> method <init>(): void
|
||||
public synthetic bridge <null> method invoke(): java.lang.Object
|
||||
public final <null> method invoke(): void
|
||||
enclosing method test/SamAdapterInInlineLambdaKt.test()V
|
||||
public final static field <null> INSTANCE: test.SamAdapterInInlineLambdaKt$test$lambda$1
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> test/SamAdapterInInlineLambdaKt {
|
||||
// source: 'samAdapterInInlineLambda.kt'
|
||||
public final static <null> method test(): void
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class<null> test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0 {
|
||||
// source: 'samAdapterInInlineLambda.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method run(): void
|
||||
enclosing class test/SamAdapterInInlineLambdaKt
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class<Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;> test/SamAdapterInInlineLambdaKt$test$lambda$1 {
|
||||
// source: 'samAdapterInInlineLambda.kt'
|
||||
static <null> method <clinit>(): void
|
||||
<null> method <init>(): void
|
||||
public synthetic bridge <null> method invoke(): java.lang.Object
|
||||
public final <null> method invoke(): void
|
||||
enclosing method test/SamAdapterInInlineLambdaKt.test()V
|
||||
public final static field <null> INSTANCE: test.SamAdapterInInlineLambdaKt$test$lambda$1
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> test/SamAdapterInInlineLambdaKt {
|
||||
// source: 'samAdapterInInlineLambda.kt'
|
||||
public final static <null> method test(): void
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$sam$java_lang_Runnable$0
|
||||
inner (anonymous) class test/SamAdapterInInlineLambdaKt$test$lambda$1
|
||||
}
|
||||
@@ -16,4 +16,5 @@ fun box(): String {
|
||||
return result
|
||||
}
|
||||
|
||||
// 1 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
|
||||
// 1 INVOKESPECIAL TestKt\$sam\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
|
||||
// 0 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
|
||||
@@ -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.<init> \(Lkotlin/jvm/functions/Function0;\)V
|
||||
// 1 INVOKESPECIAL TestKt\$sam\$i\$java_lang_Runnable\$0.<init> \(Lkotlin/jvm/functions/Function0;\)V
|
||||
+12
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+12
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user