JVM_IR: skip SAM lambdas when computing enclosing method of objects
This is what Java 15+ does, and it permits accessing captured type parameters via reflection. The alternative is to emit generic signatures on the lambda methods, but that was disabled and I have no clue why. ^KT-52417 Fixed
This commit is contained in:
+6
@@ -44955,6 +44955,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/sam/kt50477Enabled.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class FirLightTreeBlackBoxInlineCodegenTestGenerated extends AbstractFirL
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class FirSerializeCompileKotlinAgainstInlineKotlinTestGenerated extends A
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+7
-1
@@ -148,6 +148,12 @@ class ExpressionCodegen(
|
||||
|
||||
var finallyDepth = 0
|
||||
|
||||
val inlineRoot: ExpressionCodegen
|
||||
get() = inlinedInto ?: this
|
||||
|
||||
val enclosingFunctionForLocalObjects: IrFunction
|
||||
get() = generateSequence(inlineRoot.irFunction) { context.enclosingMethodOverride[it] }.last()
|
||||
|
||||
val context = classCodegen.context
|
||||
val typeMapper = context.typeMapper
|
||||
val methodSignatureMapper = context.methodSignatureMapper
|
||||
@@ -862,7 +868,7 @@ class ExpressionCodegen(
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
|
||||
if (declaration.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) {
|
||||
val childCodegen = ClassCodegen.getOrCreate(declaration, context, generateSequence(this) { it.inlinedInto }.last().irFunction)
|
||||
val childCodegen = ClassCodegen.getOrCreate(declaration, context, enclosingFunctionForLocalObjects)
|
||||
childCodegen.generate()
|
||||
closureReifiedMarkers[declaration] = childCodegen.reifiedTypeParametersUsages
|
||||
}
|
||||
|
||||
+9
-5
@@ -42,12 +42,16 @@ class IrSourceCompilerForInline(
|
||||
|
||||
override val inlineCallSiteInfo: InlineCallSiteInfo
|
||||
get() {
|
||||
val root = generateSequence(codegen) { it.inlinedInto }.last()
|
||||
val root = codegen.inlineRoot
|
||||
val rootFunction = root.enclosingFunctionForLocalObjects
|
||||
return InlineCallSiteInfo(
|
||||
root.classCodegen.type.internalName,
|
||||
root.signature.asmMethod,
|
||||
root.irFunction.inlineScopeVisibility,
|
||||
root.irFunction.fileParent.getIoFile(),
|
||||
if (rootFunction === root.irFunction)
|
||||
root.signature.asmMethod
|
||||
else
|
||||
codegen.methodSignatureMapper.mapAsmMethod(rootFunction),
|
||||
rootFunction.inlineScopeVisibility,
|
||||
rootFunction.fileParent.getIoFile(),
|
||||
callElement.psiElement?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0
|
||||
)
|
||||
}
|
||||
@@ -62,7 +66,7 @@ class IrSourceCompilerForInline(
|
||||
reifiedTypeParameters.addUsedReifiedParameter(typeParameter.name.asString())
|
||||
}
|
||||
}
|
||||
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen, reifiedTypeParameters)
|
||||
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen.inlineRoot, reifiedTypeParameters)
|
||||
}
|
||||
|
||||
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
|
||||
|
||||
@@ -367,6 +367,7 @@ private val jvmFilePhases = listOf(
|
||||
jvmSafeCallFoldingPhase,
|
||||
jvmOptimizationLoweringPhase,
|
||||
additionalClassAnnotationPhase,
|
||||
recordEnclosingMethodsPhase,
|
||||
typeOperatorLowering,
|
||||
replaceKFunctionInvokeWithFunctionInvokePhase,
|
||||
kotlinNothingValueExceptionPhase,
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineFunctionCall
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.unwrapInlineLambda
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.util.isLambda
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
internal val recordEnclosingMethodsPhase = makeIrFilePhase(
|
||||
::RecordEnclosingMethodsLowering,
|
||||
name = "RecordEnclosingMethods",
|
||||
description = "Find enclosing methods for objects inside inline and dynamic lambdas"
|
||||
)
|
||||
|
||||
private class RecordEnclosingMethodsLowering(val context: JvmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) =
|
||||
irFile.accept(object : IrElementVisitor<Unit, IrFunction?> {
|
||||
override fun visitElement(element: IrElement, data: IrFunction?) =
|
||||
element.acceptChildren(this, element as? IrFunction ?: data)
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrFunction?) {
|
||||
require(data != null) { "function call not in a method: ${expression.render()}" }
|
||||
when {
|
||||
expression.symbol == context.ir.symbols.indyLambdaMetafactoryIntrinsic -> {
|
||||
val reference = expression.getValueArgument(1)
|
||||
if (reference is IrFunctionReference && reference.origin.isLambda) {
|
||||
recordEnclosingMethodOverride(reference.symbol.owner, data)
|
||||
}
|
||||
}
|
||||
expression.symbol.owner.isInlineFunctionCall(context) -> {
|
||||
for (parameter in expression.symbol.owner.valueParameters) {
|
||||
val lambda = expression.getValueArgument(parameter.index)?.unwrapInlineLambda() ?: continue
|
||||
recordEnclosingMethodOverride(lambda.symbol.owner, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitFunctionAccess(expression, data)
|
||||
}
|
||||
|
||||
private fun recordEnclosingMethodOverride(from: IrFunction, to: IrFunction) =
|
||||
context.enclosingMethodOverride.merge(from, to) { old, new ->
|
||||
// A single lambda can be referenced multiple times if it is in a field initializer
|
||||
// or an anonymous initializer block and there are multiple non-delegating constructors.
|
||||
assert(old.parentAsClass == new.parentAsClass && old is IrConstructor && new is IrConstructor)
|
||||
old.parentAsClass.primaryConstructor ?: old
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
@@ -99,6 +99,7 @@ class JvmBackendContext(
|
||||
}
|
||||
|
||||
val isEnclosedInConstructor = ConcurrentHashMap.newKeySet<IrAttributeContainer>()
|
||||
val enclosingMethodOverride = ConcurrentHashMap<IrFunction, IrFunction>()
|
||||
|
||||
private val classCodegens = ConcurrentHashMap<IrClass, Any>()
|
||||
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// WITH_STDLIB
|
||||
package test
|
||||
|
||||
abstract class TypeToken<T>
|
||||
|
||||
fun interface I {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun <T> foo() =
|
||||
I {
|
||||
(object : TypeToken<T>() {})::class.java.genericSuperclass.toString()
|
||||
}.foo()
|
||||
|
||||
fun box(): String =
|
||||
foo<String>().let { if (it == "test.TypeToken<T>") "OK" else it }
|
||||
@@ -0,0 +1,28 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// WITH_STDLIB
|
||||
// FILE: 1.kt
|
||||
package test
|
||||
|
||||
abstract class TypeToken<U>
|
||||
|
||||
// Although V is not reified, if the object happens to be regenerated, V will be replaced with its value in signatures
|
||||
inline fun <V> typeTokenOf(crossinline forceRegeneration: () -> Unit = {}) =
|
||||
object : TypeToken<V>() {
|
||||
fun unused() = forceRegeneration()
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
import test.*
|
||||
|
||||
fun interface I {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun <T> foo() =
|
||||
I {
|
||||
typeTokenOf<T>()::class.java.genericSuperclass.toString()
|
||||
}.foo()
|
||||
|
||||
fun box(): String =
|
||||
foo<String>().let { if (it == "test.TypeToken<T>") "OK" else it }
|
||||
+6
@@ -44391,6 +44391,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/sam/kt50171.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -44955,6 +44955,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/sam/kt50477Enabled.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class IrSerializeCompileKotlinAgainstInlineKotlinTestGenerated extends Ab
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+6
@@ -2230,6 +2230,12 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/enclosingInfo/kt52417.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("objectInInlineFun.kt")
|
||||
public void testObjectInInlineFun() throws Exception {
|
||||
|
||||
+5
@@ -35870,6 +35870,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/sam/kt50171.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt52417.kt")
|
||||
public void testKt52417() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt52417.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt");
|
||||
|
||||
Reference in New Issue
Block a user