diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBytecodeTextTestGenerated.java index 1ff67771358..5bd3fe59e86 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBytecodeTextTestGenerated.java @@ -4314,6 +4314,11 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("samWrapperConstructorNonSynthetic.kt") + public void testSamWrapperConstructorNonSynthetic() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt"); + } + @TestMetadata("samWrapperForNullInitialization.kt") public void testSamWrapperForNullInitialization() throws Exception { runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt"); diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt index 026e0ccdbc9..ffa170a558b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt @@ -69,6 +69,10 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : protected open fun getWrappedFunctionType(klass: IrClass): IrType = klass.defaultType + protected open fun IrFunctionBuilder.setConstructorSourceRange(createFor: IrElement) { + setSourceRange(createFor) + } + abstract val IrType.needEqualsHashCodeMethods: Boolean open val inInlineFunctionScope get() = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false } @@ -187,10 +191,10 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : } subclass.addConstructor { - origin = subclass.origin + origin = IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION isPrimary = true visibility = wrapperVisibility - setSourceRange(createFor) + setConstructorSourceRange(createFor) }.apply { val parameter = addValueParameter { name = field.name diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index ff207eabad7..26a7fbbaf15 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -18,7 +18,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.isMultifileBridge import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.* -import org.jetbrains.kotlin.codegen.DescriptorAsmUtil.* +import org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getNameForReceiverParameter import org.jetbrains.kotlin.codegen.coroutines.SuspensionPointKind import org.jetbrains.kotlin.codegen.coroutines.generateCoroutineSuspendedCheck import org.jetbrains.kotlin.codegen.inline.* @@ -48,7 +48,8 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.jvm.AsmTypes -import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext @@ -285,7 +286,9 @@ class ExpressionCodegen( irFunction.origin.isSynthetic || // TODO: refine this condition to not generate nullability assertions on parameters // corresponding to captured variables and anonymous object super constructor arguments - (irFunction is IrConstructor && irFunction.parentAsClass.isAnonymousObject) || + (irFunction is IrConstructor && + (irFunction.parentAsClass.isAnonymousObject || + irFunction.parentAsClass.origin == IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION)) || // TODO: Implement this as a lowering, so that we can more easily exclude generated methods. irFunction.origin == JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD || // Although these are accessible from Java, the functions they bridge to already have the assertions. 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 0ac7ec016c3..f90d7bce15b 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 @@ -12,6 +12,9 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound 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.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrFunction @@ -47,6 +50,13 @@ private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : Sing override fun getWrappedFunctionType(klass: IrClass): IrType = klass.symbol.rawType(context as JvmBackendContext) + // The constructor of a SAM wrapper is non-synthetic and should not have line numbers. + // Otherwise the debugger will try to step into it. + override fun IrFunctionBuilder.setConstructorSourceRange(createFor: IrElement) { + startOffset = UNDEFINED_OFFSET + endOffset = UNDEFINED_OFFSET + } + private val IrType.isKotlinFunInterface: Boolean get() = getClass()?.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt new file mode 100644 index 00000000000..3c52a199bb4 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt @@ -0,0 +1,24 @@ +// FILE: J.java + +public class J { + public static void g(Runnable r) { + r.run(); + } +} + +// FILE: test.kt + +fun nonInlineFun() { + val f = {} + J.g(f) +} + +inline fun inlineFun() { + val f = {} + J.g(f) +} + +// The SAM wrapper constructor is public inside of inline functions. +// It has no other flags. In particular, it is not synthetic. +// 1 access flags 0x0\n\s*\(Lkotlin/jvm/functions/Function0;\)V +// 1 access flags 0x1\n\s*public \(Lkotlin/jvm/functions/Function0;\)V diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 155ac4ea16e..a1c09a4937e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -4386,6 +4386,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("samWrapperConstructorNonSynthetic.kt") + public void testSamWrapperConstructorNonSynthetic() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt"); + } + @TestMetadata("samWrapperForNullInitialization.kt") public void testSamWrapperForNullInitialization() throws Exception { runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 8703c13bdf4..6fa273af54a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -4314,6 +4314,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("samWrapperConstructorNonSynthetic.kt") + public void testSamWrapperConstructorNonSynthetic() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt"); + } + @TestMetadata("samWrapperForNullInitialization.kt") public void testSamWrapperForNullInitialization() throws Exception { runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt");