JVM_IR: propagate reified type parameter usages from inline lambdas
...to whichever class they are inlined into, not the class they are declared in (which is not the same if the lambda is crossinline). #KT-46584 Fixed
This commit is contained in:
@@ -58,6 +58,8 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
|
||||
|
||||
lateinit var node: SMAPAndMethodNode
|
||||
|
||||
val reifiedTypeParametersUsages = ReifiedTypeParametersUsages()
|
||||
|
||||
abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>)
|
||||
|
||||
open val hasDispatchReceiver = true
|
||||
@@ -198,7 +200,7 @@ abstract class DefaultLambda(
|
||||
|
||||
if (needReification) {
|
||||
//nested classes could also require reification
|
||||
reifiedTypeInliner.reifyInstructions(node.node)
|
||||
reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(node.node))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +227,7 @@ internal fun Type.boxReceiverForBoundReference(kotlinType: KotlinType, typeMappe
|
||||
|
||||
abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInline) {
|
||||
override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) {
|
||||
node = sourceCompiler.generateLambdaBody(this)
|
||||
node = sourceCompiler.generateLambdaBody(this, reifiedTypeParametersUsages)
|
||||
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
|
||||
}
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ class MethodInliner(
|
||||
visitInsn(Opcodes.NOP)
|
||||
}
|
||||
|
||||
inlineOnlySmapSkipper?.onInlineLambdaStart(remappingMethodAdapter, info, sourceMapper.parent)
|
||||
inlineOnlySmapSkipper?.onInlineLambdaStart(remappingMethodAdapter, info.node.node, sourceMapper.parent)
|
||||
addInlineMarker(this, true)
|
||||
val lambdaParameters = info.addAllParameters(nodeRemapper)
|
||||
|
||||
@@ -289,6 +289,7 @@ class MethodInliner(
|
||||
val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift)
|
||||
result.mergeWithNotChangeInfo(lambdaResult)
|
||||
result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages)
|
||||
result.reifiedTypeParametersUsages.mergeAll(info.reifiedTypeParametersUsages)
|
||||
|
||||
StackValue
|
||||
.onStack(info.invokeMethod.returnType, info.invokeMethodReturnType)
|
||||
|
||||
@@ -48,7 +48,7 @@ interface SourceCompilerForInline {
|
||||
|
||||
val lazySourceMapper: SourceMapper
|
||||
|
||||
fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode
|
||||
fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode
|
||||
|
||||
fun doCreateMethodNodeFromSource(
|
||||
callableDescriptor: FunctionDescriptor,
|
||||
@@ -130,7 +130,7 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
override val lazySourceMapper
|
||||
get() = codegen.parentCodegen.orCreateSourceMapper
|
||||
|
||||
override fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode {
|
||||
override fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode {
|
||||
lambdaInfo as? PsiExpressionLambda ?: error("TODO")
|
||||
val invokeMethodDescriptor = lambdaInfo.invokeMethodDescriptor
|
||||
val jvmMethodSignature = state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor)
|
||||
|
||||
@@ -579,8 +579,8 @@ class InlineOnlySmapSkipper(codegen: BaseExpressionCodegen) {
|
||||
const val LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER = 1
|
||||
}
|
||||
|
||||
fun onInlineLambdaStart(mv: MethodVisitor, info: LambdaInfo, smap: SourceMapper) {
|
||||
val firstLine = info.node.node.instructions.asSequence().mapNotNull { it as? LineNumberNode }.firstOrNull()?.line ?: -1
|
||||
fun onInlineLambdaStart(mv: MethodVisitor, lambda: MethodNode, smap: SourceMapper) {
|
||||
val firstLine = lambda.instructions.asSequence().mapNotNull { it as? LineNumberNode }.firstOrNull()?.line ?: -1
|
||||
if (callLineNumber >= 0 && firstLine == callLineNumber) {
|
||||
// We want the debugger to be able to break both on the inline call itself, plus on each
|
||||
// invocation of the inline lambda passed to it. For that to happen there needs to be at least
|
||||
|
||||
+12
@@ -3714,6 +3714,18 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+4
-22
@@ -143,6 +143,7 @@ class ExpressionCodegen(
|
||||
val classCodegen: ClassCodegen,
|
||||
val inlinedInto: ExpressionCodegen?,
|
||||
val smap: SourceMapper,
|
||||
val reifiedTypeParametersUsages: ReifiedTypeParametersUsages,
|
||||
) : IrElementVisitor<PromisedValue, BlockInfo>, BaseExpressionCodegen {
|
||||
|
||||
var finallyDepth = 0
|
||||
@@ -1426,32 +1427,13 @@ class ExpressionCodegen(
|
||||
|
||||
override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) {
|
||||
require(typeParameter is IrTypeParameterSymbol)
|
||||
// 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 <reified T : Any> 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 <reified T : Any> 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())
|
||||
if (irFunction != typeParameter.owner.parent) {
|
||||
reifiedTypeParametersUsages.addUsedReifiedParameter(typeParameter.owner.name.asString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) {
|
||||
classCodegen.reifiedTypeParametersUsages.propagateChildUsagesWithinContext(reifiedTypeParametersUsages) {
|
||||
this.reifiedTypeParametersUsages.propagateChildUsagesWithinContext(reifiedTypeParametersUsages) {
|
||||
irFunction.typeParameters.filter { it.isReified }.map { it.name.asString() }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
+11
-13
@@ -13,10 +13,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.inline.MethodBodyVisitor
|
||||
import org.jetbrains.kotlin.codegen.inline.SMAP
|
||||
import org.jetbrains.kotlin.codegen.inline.SMAPAndMethodNode
|
||||
import org.jetbrains.kotlin.codegen.inline.wrapWithMaxLocalCalc
|
||||
import org.jetbrains.kotlin.codegen.inline.*
|
||||
import org.jetbrains.kotlin.codegen.mangleNameIfNeeded
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.visitAnnotableParameterCount
|
||||
@@ -40,21 +37,20 @@ import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class FunctionCodegen(
|
||||
private val irFunction: IrFunction,
|
||||
private val classCodegen: ClassCodegen,
|
||||
private val inlinedInto: ExpressionCodegen? = null
|
||||
) {
|
||||
class FunctionCodegen(private val irFunction: IrFunction, private val classCodegen: ClassCodegen) {
|
||||
private val context = classCodegen.context
|
||||
|
||||
fun generate(): SMAPAndMethodNode =
|
||||
fun generate(
|
||||
inlinedInto: ExpressionCodegen? = null,
|
||||
reifiedTypeParameters: ReifiedTypeParametersUsages = classCodegen.reifiedTypeParametersUsages
|
||||
): SMAPAndMethodNode =
|
||||
try {
|
||||
doGenerate()
|
||||
doGenerate(inlinedInto, reifiedTypeParameters)
|
||||
} catch (e: Throwable) {
|
||||
throw RuntimeException("Exception while generating code for:\n${irFunction.dump()}", e)
|
||||
}
|
||||
|
||||
private fun doGenerate(): SMAPAndMethodNode {
|
||||
private fun doGenerate(inlinedInto: ExpressionCodegen?, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode {
|
||||
val signature = context.methodSignatureMapper.mapSignatureWithGeneric(irFunction)
|
||||
val flags = irFunction.calculateMethodFlags()
|
||||
val isSynthetic = flags.and(Opcodes.ACC_SYNTHETIC) != 0
|
||||
@@ -121,7 +117,9 @@ class FunctionCodegen(
|
||||
context.state.globalInlineContext.enterDeclaration(irFunction.suspendFunctionOriginal().toIrBasedDescriptor())
|
||||
try {
|
||||
val adapter = InstructionAdapter(methodVisitor)
|
||||
ExpressionCodegen(irFunction, signature, frameMap, adapter, classCodegen, inlinedInto, sourceMapper).generate()
|
||||
ExpressionCodegen(
|
||||
irFunction, signature, frameMap, adapter, classCodegen, inlinedInto, sourceMapper, reifiedTypeParameters
|
||||
).generate()
|
||||
} finally {
|
||||
context.state.globalInlineContext.exitDeclaration()
|
||||
}
|
||||
|
||||
+10
-3
@@ -95,8 +95,15 @@ class IrSourceCompilerForInline(
|
||||
override val lazySourceMapper: SourceMapper
|
||||
get() = codegen.smap
|
||||
|
||||
override fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode =
|
||||
FunctionCodegen((lambdaInfo as IrExpressionLambdaImpl).function, codegen.classCodegen, codegen).generate()
|
||||
override fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode {
|
||||
require(lambdaInfo is IrExpressionLambdaImpl)
|
||||
for (typeParameter in lambdaInfo.function.typeParameters) {
|
||||
if (typeParameter.isReified) {
|
||||
reifiedTypeParameters.addUsedReifiedParameter(typeParameter.name.asString())
|
||||
}
|
||||
}
|
||||
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen, reifiedTypeParameters)
|
||||
}
|
||||
|
||||
override fun doCreateMethodNodeFromSource(
|
||||
callableDescriptor: FunctionDescriptor,
|
||||
@@ -116,7 +123,7 @@ class IrSourceCompilerForInline(
|
||||
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
|
||||
ExpressionCodegen(
|
||||
codegen.irFunction, codegen.signature, codegen.frameMap, InstructionAdapter(finallyNode), codegen.classCodegen,
|
||||
codegen.inlinedInto, codegen.smap
|
||||
codegen.inlinedInto, codegen.smap, codegen.reifiedTypeParametersUsages
|
||||
).also {
|
||||
it.finallyDepth = curFinallyDepth
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// FILE: 1.kt
|
||||
package test
|
||||
|
||||
inline fun foo(crossinline x: () -> String) = { x() }()
|
||||
|
||||
inline fun <reified T> bar() = foo { { T::class.simpleName!! }() }
|
||||
|
||||
// FILE: 2.kt
|
||||
import test.*
|
||||
|
||||
class OK
|
||||
|
||||
fun box() = bar<OK>()
|
||||
@@ -0,0 +1,13 @@
|
||||
// FILE: 1.kt
|
||||
package test
|
||||
|
||||
inline fun foo(x: () -> String) = x()
|
||||
|
||||
inline fun <reified T> bar() = { foo { { T::class.simpleName!! }() } }()
|
||||
|
||||
// FILE: 2.kt
|
||||
import test.*
|
||||
|
||||
class OK
|
||||
|
||||
fun box() = bar<OK>()
|
||||
+12
@@ -3714,6 +3714,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+12
@@ -3714,6 +3714,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+12
@@ -3714,6 +3714,18 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+12
@@ -3714,6 +3714,18 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+12
@@ -3714,6 +3714,18 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+12
@@ -3714,6 +3714,18 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt44770_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6988.kt")
|
||||
public void testKt6988() throws Exception {
|
||||
|
||||
+10
@@ -3025,6 +3025,16 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt35511_try_values.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt7017.kt")
|
||||
public void testKt7017() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt7017.kt");
|
||||
|
||||
Generated
+10
@@ -3025,6 +3025,16 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt35511_try_values.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt7017.kt")
|
||||
public void testKt7017() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt7017.kt");
|
||||
|
||||
Generated
+10
@@ -3025,6 +3025,16 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt35511_try_values.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt46584.kt")
|
||||
public void testKt46584() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt46584_2.kt")
|
||||
public void testKt46584_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt46584_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt7017.kt")
|
||||
public void testKt7017() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/reified/kt7017.kt");
|
||||
|
||||
Reference in New Issue
Block a user