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 a8b590b7726..6e25ee77403 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 @@ -100,7 +100,7 @@ class ExpressionCodegen( override val frameMap: IrFrameMap, val mv: InstructionAdapter, val classCodegen: ClassCodegen, - val isInlineLambda: Boolean = false + val inlinedInto: ExpressionCodegen? ) : IrElementVisitor, BaseExpressionCodegen { var finallyDepth = 0 @@ -202,7 +202,7 @@ class ExpressionCodegen( if (state.isParamAssertionsDisabled) return - val notCallableFromJava = isInlineLambda || + val notCallableFromJava = inlinedInto != null || Visibilities.isPrivate(irFunction.visibility) || irFunction.origin.isSynthetic || // TODO: refine this condition to not generate nullability assertions on parameters @@ -314,7 +314,7 @@ class ExpressionCodegen( visitStatementContainer(expression, data).coerce(expression.type) override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue { - return visitFunctionAccess(expression.createSuspendFunctionCallViewIfNeeded(context, irFunction, isInlineLambda), data) + return visitFunctionAccess(expression.createSuspendFunctionCallViewIfNeeded(context, irFunction, inlinedInto != null), data) } override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: BlockInfo): PromisedValue { @@ -1012,7 +1012,26 @@ class ExpressionCodegen( override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) { require(typeParameter is IrTypeParameterSymbol) - if (typeParameter.owner.parent != irFunction) { + // This is a hack to work around the problem in LocalDeclarationsLowering. Specifically, suppose an inline + // lambda uses a reified type parameter declared by a function: + // + // object { + // inline fun f() = run { T::class.java.getName() } + // } + // + // LocalDeclarationsLowering would extract that lambda into a method of the enclosing type, but will not create + // a reified type parameter in it (in fact, the lambda method isn't even marked as inline): + // + // object { + // /* static */ private fun `f$lambda-0`() = T::class.java.getName() + // inline fun f() = run(::`f$lambda-0`) + // } + // + // The parent of the type parameter then is not `irFunction` (i.e. the lambda itself), but the function + // it is inlined into. + // + // TODO make LocalDeclarationsLowering handle captured type parameters and only compare with `irFunction`. + if (generateSequence(this) { it.inlinedInto }.none { it.irFunction == typeParameter.owner.parent }) { classCodegen.reifiedTypeParametersUsages.addUsedReifiedParameter(typeParameter.owner.name.asString()) } } @@ -1039,7 +1058,7 @@ class ExpressionCodegen( } fun isFinallyMarkerRequired(): Boolean { - return irFunction.isInline || isInlineLambda + return irFunction.isInline || inlinedInto != null } private val IrType.isReifiedTypeParameter: Boolean diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index a3c0716a021..7c6a2ee0777 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -30,7 +30,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter open class FunctionCodegen( private val irFunction: IrFunction, private val classCodegen: ClassCodegen, - private val isInlineLambda: Boolean = false + private val inlinedInto: ExpressionCodegen? = null ) { val context = classCodegen.context val state = classCodegen.state @@ -95,7 +95,7 @@ open class FunctionCodegen( ) else -> methodVisitor } - ExpressionCodegen(functionView, signature, frameMap, InstructionAdapter(methodVisitor), classCodegen, isInlineLambda).generate() + ExpressionCodegen(functionView, signature, frameMap, InstructionAdapter(methodVisitor), classCodegen, inlinedInto).generate() methodVisitor.visitMaxs(-1, -1) continuationClassBuilder?.done() } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index b549af5397b..4ec3bb351e6 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -74,7 +74,7 @@ class IrSourceCompilerForInline( private fun makeInlineNode(function: IrFunction, classCodegen: ClassCodegen, isLambda: Boolean): SMAPAndMethodNode { var node: MethodNode? = null - val functionCodegen = object : FunctionCodegen(function, classCodegen, isLambda) { + val functionCodegen = object : FunctionCodegen(function, classCodegen, codegen.takeIf { isLambda }) { override fun createMethod(flags: Int, signature: JvmMethodGenericSignature): MethodVisitor { val asmMethod = signature.asmMethod node = MethodNode(Opcodes.API_VERSION, flags, asmMethod.name, asmMethod.descriptor, signature.genericsSignature, null) @@ -134,7 +134,7 @@ class IrSourceCompilerForInline( override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) = ExpressionCodegen( codegen.irFunction, codegen.signature, codegen.frameMap, InstructionAdapter(finallyNode), codegen.classCodegen, - codegen.isInlineLambda + codegen.inlinedInto ).also { it.finallyDepth = curFinallyDepth } diff --git a/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt b/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt index 681c7ae2517..ae7d058fa46 100644 --- a/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt +++ b/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME