JVM: fix EnclosingMethod information for SAMs in inline lambdas
Pass parentContext to SamWrapperCodegen from the outside instead of using the one from parentCodegen. The difference is that in case of an inline lambda, we're creating an InlineLambdaContext whose parent is a ClosureContext, but the codegen for that lambda has that latter ClosureContext as its context. So the getNonInlineOuterContext call in SamWrapperCodegen.generateInnerClassInformation wasn't able to identify that this is a context of a lambda that needs to be skipped, and generated it as EnclosingMethod, which caused Java reflection to fail because once that lambda was inlined, it was removed and thus didn't make it to runtime. #KT-44827 Fixed
This commit is contained in:
@@ -36,14 +36,16 @@ class SamWrapperClasses(private val state: GenerationState) {
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
contextDescriptor: CallableMemberDescriptor
|
||||
): Type {
|
||||
val isInsideInline = InlineUtil.isInlineOrContainingInline(expressionCodegen.context.contextDescriptor) ||
|
||||
isInsideInlineLambdaContext(expressionCodegen.context, state)
|
||||
val parentContext = expressionCodegen.context
|
||||
val isInsideInline = InlineUtil.isInlineOrContainingInline(parentContext.contextDescriptor) ||
|
||||
isInsideInlineLambdaContext(parentContext, state)
|
||||
return samInterfaceToWrapperClass.getOrPut(WrapperKey(samType, file, isInsideInline)) {
|
||||
SamWrapperCodegen(state, samType, expressionCodegen.parentCodegen, isInsideInline).genWrapper(file, contextDescriptor)
|
||||
SamWrapperCodegen(state, samType, expressionCodegen.parentCodegen, parentContext, isInsideInline)
|
||||
.genWrapper(file, contextDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInsideInlineLambdaContext(context: CodegenContext<*>, state: GenerationState):Boolean {
|
||||
private fun isInsideInlineLambdaContext(context: CodegenContext<*>, state: GenerationState): Boolean {
|
||||
var parent: CodegenContext<*>? = context
|
||||
while (parent != null && parent != state.rootContext) {
|
||||
if (parent is InlineLambdaContext) return true
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.context.ClassContext;
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
@@ -64,6 +63,7 @@ public class SamWrapperCodegen {
|
||||
private final KotlinTypeMapper typeMapper;
|
||||
private final SamType samType;
|
||||
private final MemberCodegen<?> parentCodegen;
|
||||
private final CodegenContext<?> parentContext;
|
||||
private final int visibility;
|
||||
private final int classFlags;
|
||||
public static final String SAM_WRAPPER_SUFFIX = "$0";
|
||||
@@ -72,6 +72,7 @@ public class SamWrapperCodegen {
|
||||
@NotNull GenerationState state,
|
||||
@NotNull SamType samType,
|
||||
@NotNull MemberCodegen<?> parentCodegen,
|
||||
@NotNull CodegenContext<?> parentContext,
|
||||
boolean isInsideInline
|
||||
) {
|
||||
this.state = state;
|
||||
@@ -79,6 +80,7 @@ public class SamWrapperCodegen {
|
||||
this.typeMapper = state.getTypeMapper();
|
||||
this.samType = samType;
|
||||
this.parentCodegen = parentCodegen;
|
||||
this.parentContext = parentContext;
|
||||
visibility = isInsideInline ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
|
||||
int synth = state.getLanguageVersionSettings().supportsFeature(LanguageFeature.SamWrapperClassesAreSynthetic) ? ACC_SYNTHETIC : 0;
|
||||
classFlags = visibility | ACC_FINAL | ACC_SUPER | synth;
|
||||
@@ -170,7 +172,6 @@ public class SamWrapperCodegen {
|
||||
|
||||
private void generateInnerClassInformation(@NotNull KtFile file, Type asmType, ClassBuilder cv) {
|
||||
parentCodegen.addSyntheticAnonymousInnerClass(new SyntheticInnerClassInfo(asmType.getInternalName(), classFlags));
|
||||
FieldOwnerContext<?> parentContext = parentCodegen.context;
|
||||
CodegenContext<?> outerContext = MemberCodegen.getNonInlineOuterContext(parentContext);
|
||||
assert outerContext != null :
|
||||
"Outer context for SAM wrapper " + asmType.getInternalName() + " is null, parentContext:" + parentContext;
|
||||
|
||||
+12
@@ -15184,6 +15184,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/funInterface/irrelevantPrivateDeclarations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44827_funInterface.kt")
|
||||
public void testKt44827_funInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/kt44827_funInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimodule.kt")
|
||||
public void testMultimodule() throws Exception {
|
||||
@@ -37074,6 +37080,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44827_sam.kt")
|
||||
public void testKt44827_sam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt44827_sam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt4753.kt")
|
||||
public void testKt4753() throws Exception {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun interface J {
|
||||
operator fun invoke(): String
|
||||
}
|
||||
|
||||
fun invoke(j: J): String {
|
||||
// Check that there's something sensible in the EnclosingMethod; crashes if it's not the case.
|
||||
j.javaClass.enclosingMethod
|
||||
|
||||
return j()
|
||||
}
|
||||
|
||||
class A(val result: String)
|
||||
|
||||
fun box(): String {
|
||||
var a = A("OK")
|
||||
return 42.let {
|
||||
invoke(a::result)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: test.kt
|
||||
|
||||
fun invoke(j: J): String {
|
||||
// Check that there's something sensible in the EnclosingMethod; crashes if it's not the case.
|
||||
j.javaClass.enclosingMethod
|
||||
|
||||
return j()
|
||||
}
|
||||
|
||||
class A(val result: String)
|
||||
|
||||
fun box(): String {
|
||||
var a = A("OK")
|
||||
return 42.let {
|
||||
invoke(a::result)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
public interface J {
|
||||
String invoke();
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
public <null> method getFunctionDelegate(): kotlin.Function
|
||||
public <null> method hashCode(): int
|
||||
enclosing class TKt
|
||||
enclosing method TKt.genericSam()Ljava/lang/Object;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
// source: 't.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
enclosing class TKt
|
||||
enclosing method TKt.genericSam()Ljava/lang/Object;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
public <null> method getFunctionDelegate(): kotlin.Function
|
||||
public <null> method hashCode(): int
|
||||
enclosing class TKt
|
||||
enclosing method TKt.specializedSam()Ljava/lang/String;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
// source: 't.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
enclosing class TKt
|
||||
enclosing method TKt.specializedSam()Ljava/lang/String;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
public <null> method getFunctionDelegate(): kotlin.Function
|
||||
public <null> method hashCode(): int
|
||||
enclosing class TKt
|
||||
enclosing method TKt.genericSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
// source: 't.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
enclosing class TKt
|
||||
enclosing method TKt.genericSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class<null> TKt$sam$Sam$0 {
|
||||
// source: 't.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
enclosing class TKt
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> TKt {
|
||||
// source: 't.kt'
|
||||
public final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class A$sam$java_lang_Runnable$0 {
|
||||
// source: 'reusedSamWrapperClasses.kt'
|
||||
enclosing class A
|
||||
enclosing method A.test1()V
|
||||
private synthetic final field function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class A$sam$java_lang_Runnable$0
|
||||
method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class A$sam$java_lang_Runnable$0 {
|
||||
// source: 'reusedSamWrapperClasses.kt'
|
||||
enclosing class A
|
||||
private synthetic final field function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class A$sam$java_lang_Runnable$0
|
||||
method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final method run(): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class A$test1$f$1 {
|
||||
// source: 'reusedSamWrapperClasses.kt'
|
||||
enclosing method A.test1()V
|
||||
public final static field INSTANCE: A$test1$f$1
|
||||
inner (anonymous) class A$test1$f$1
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public synthetic bridge method invoke(): java.lang.Object
|
||||
public final method invoke(): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class A {
|
||||
// source: 'reusedSamWrapperClasses.kt'
|
||||
inner (anonymous) class A$sam$java_lang_Runnable$0
|
||||
inner (anonymous) class A$test1$f$1
|
||||
public method <init>(): void
|
||||
public final method test1(): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class B$test2$f$1 {
|
||||
// source: 'reusedSamWrapperClasses.kt'
|
||||
enclosing method B.test2()V
|
||||
public final static field INSTANCE: B$test2$f$1
|
||||
inner (anonymous) class B$test2$f$1
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public synthetic bridge method invoke(): java.lang.Object
|
||||
public final method invoke(): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class B {
|
||||
// source: 'reusedSamWrapperClasses.kt'
|
||||
inner (anonymous) class B$test2$f$1
|
||||
public method <init>(): void
|
||||
public final method test2(): void
|
||||
}
|
||||
@@ -3,7 +3,7 @@ public synthetic final class<null> test/SamAdapterAndInlinedOneKt$sam$i$java_la
|
||||
// source: 'samAdapterAndInlinedOne.kt'
|
||||
public <null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method run(): void
|
||||
enclosing class test/SamAdapterAndInlinedOneKt
|
||||
enclosing method test/SamAdapterAndInlinedOneKt.makeRunnable(Lkotlin/jvm/functions/Function0;)Ljava/lang/Runnable;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class test/SamAdapterAndInlinedOneKt$sam$i$java_lang_Runnable$0
|
||||
}
|
||||
@@ -13,7 +13,7 @@ synthetic final class<null> test/SamAdapterAndInlinedOneKt$sam$java_lang_Runnab
|
||||
// source: 'samAdapterAndInlinedOne.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method run(): void
|
||||
enclosing class test/SamAdapterAndInlinedOneKt
|
||||
enclosing method test/SamAdapterAndInlinedOneKt.noInline(Lkotlin/jvm/functions/Function0;)Ljava/lang/Runnable;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class test/SamAdapterAndInlinedOneKt$sam$java_lang_Runnable$0
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
public <null> method getFunctionDelegate(): kotlin.Function
|
||||
public <null> method hashCode(): int
|
||||
enclosing class TKt
|
||||
enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ synthetic final class<null> TKt$sam$Sam$0 {
|
||||
// source: 't.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
enclosing class TKt
|
||||
enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class<null> TKt$sam$Sam$0 {
|
||||
// source: 't.kt'
|
||||
<null> method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
public synthetic final <null> method get(): java.lang.Object
|
||||
enclosing class TKt
|
||||
private synthetic final field <null> function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class<null> TKt {
|
||||
// source: 't.kt'
|
||||
public final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
|
||||
inner (anonymous) class TKt$sam$Sam$0
|
||||
}
|
||||
+1
-1
@@ -61,7 +61,7 @@ public final class B$runnable2$1 {
|
||||
@kotlin.Metadata
|
||||
public synthetic final class B$sam$i$java_lang_Runnable$0 {
|
||||
// source: 'wrapperInlinedFromAnotherClass.kt'
|
||||
enclosing class B
|
||||
enclosing method B.runnableSamCtor(Lkotlin/jvm/functions/Function0;)Ljava/lang/Runnable;
|
||||
private synthetic final field function: kotlin.jvm.functions.Function0
|
||||
inner (anonymous) class B$sam$i$java_lang_Runnable$0
|
||||
public method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||
|
||||
+12
@@ -15184,6 +15184,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/funInterface/irrelevantPrivateDeclarations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44827_funInterface.kt")
|
||||
public void testKt44827_funInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/kt44827_funInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimodule.kt")
|
||||
public void testMultimodule() throws Exception {
|
||||
@@ -37074,6 +37080,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44827_sam.kt")
|
||||
public void testKt44827_sam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt44827_sam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt4753.kt")
|
||||
public void testKt4753() throws Exception {
|
||||
|
||||
+12
@@ -15184,6 +15184,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/funInterface/irrelevantPrivateDeclarations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44827_funInterface.kt")
|
||||
public void testKt44827_funInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/kt44827_funInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimodule.kt")
|
||||
public void testMultimodule() throws Exception {
|
||||
@@ -37074,6 +37080,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44827_sam.kt")
|
||||
public void testKt44827_sam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt44827_sam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt4753.kt")
|
||||
public void testKt4753() throws Exception {
|
||||
|
||||
+10
@@ -12550,6 +12550,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/funInterface/irrelevantPrivateDeclarations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt44827_funInterface.kt")
|
||||
public void testKt44827_funInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/kt44827_funInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multimodule.kt")
|
||||
public void testMultimodule() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
|
||||
@@ -29569,6 +29574,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt44827_sam.kt")
|
||||
public void testKt44827_sam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt44827_sam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt4753.kt")
|
||||
public void testKt4753() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt4753.kt");
|
||||
|
||||
Reference in New Issue
Block a user