JVM_IR: do not deep-copy suspend lambdas in initializers
This loses reflection metadata (and also sometimes fails). Which was missing anyway - this is also fixed now. #KT-42554 Fixed
This commit is contained in:
Generated
+5
@@ -27008,6 +27008,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
public void testReflectOnLambdaInSuspendLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInSuspendLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("reflectOnSuspendLambdaInField.kt")
|
||||
public void testReflectOnSuspendLambdaInField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnSuspendLambdaInField.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
|
||||
|
||||
@@ -102,6 +102,12 @@ internal val propertiesPhase = makeIrFilePhase(
|
||||
stickyPostconditions = setOf((PropertiesLowering)::checkNoProperties)
|
||||
)
|
||||
|
||||
internal val IrClass.isGeneratedLambdaClass: Boolean
|
||||
get() = origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
|
||||
origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA ||
|
||||
origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
|
||||
origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||
|
||||
internal val localDeclarationsPhase = makeIrFilePhase(
|
||||
{ context ->
|
||||
LocalDeclarationsLowering(
|
||||
@@ -111,12 +117,10 @@ internal val localDeclarationsPhase = makeIrFilePhase(
|
||||
NameUtils.sanitizeAsJavaIdentifier(super.localName(declaration))
|
||||
},
|
||||
object : VisibilityPolicy {
|
||||
// Note: any condition that results in non-`LOCAL` visibility here should be duplicated in `JvmLocalClassPopupLowering`,
|
||||
// else it won't detect the class as local.
|
||||
override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
|
||||
declaration.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA ||
|
||||
declaration.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
|
||||
declaration.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||
) {
|
||||
if (declaration.isGeneratedLambdaClass) {
|
||||
scopedVisibility(inInlineFunctionScope)
|
||||
} else {
|
||||
declaration.visibility
|
||||
|
||||
+5
-8
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.LocalClassPopupLowering
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
|
||||
import org.jetbrains.kotlin.backend.jvm.isGeneratedLambdaClass
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
|
||||
@@ -31,15 +32,11 @@ class JvmLocalClassPopupLowering(context: JvmBackendContext) : LocalClassPopupLo
|
||||
// On JVM, we only pop up local classes in field initializers and anonymous init blocks, so that InitializersLowering would not copy
|
||||
// them to each constructor. (Moving all local classes is not possible because of cases where they use reified type parameters,
|
||||
// or capture crossinline lambdas.)
|
||||
// Upon moving such class, we record customEnclosingFunction for it to be the class constructor. This is needed because otherwise
|
||||
// the class will not get any EnclosingMethod in the codegen later, since it won't be local anymore.
|
||||
// Upon moving such class, we record that it used to be in an initializer so that the codegen later sets its EnclosingMethod
|
||||
// to the primary constructor.
|
||||
override fun shouldPopUp(klass: IrClass, currentScope: ScopeWithIr?): Boolean {
|
||||
// On JVM, lambdas have package-private visibility after LocalDeclarationsLowering, so we have to check something else.
|
||||
val isLocal = super.shouldPopUp(klass, currentScope) ||
|
||||
klass.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
|
||||
klass.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
|
||||
klass.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||
if (!isLocal) return false
|
||||
// On JVM, lambdas have package-private visibility after LocalDeclarationsLowering; see `forClass` in `localDeclarationsPhase`.
|
||||
if (!super.shouldPopUp(klass, currentScope) && !klass.isGeneratedLambdaClass) return false
|
||||
|
||||
var parent = currentScope?.irElement
|
||||
while (parent is IrFunction) {
|
||||
|
||||
+1
@@ -187,6 +187,7 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
||||
addInvokeCallingConstructor(constructor, invokeSuspend, invokeToOverride, parametersFields)
|
||||
}
|
||||
|
||||
this.metadata = function.metadata
|
||||
context.suspendLambdaToOriginalFunctionMap[attributeOwnerId as IrFunctionReference] = function
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.jvm.reflect
|
||||
|
||||
class C {
|
||||
val x: suspend (String) -> Unit = { OK: String -> }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return C().x.reflect()?.parameters?.singleOrNull()?.name ?: "null"
|
||||
}
|
||||
+5
@@ -28774,6 +28774,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
public void testReflectOnLambdaInSuspendLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInSuspendLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("reflectOnSuspendLambdaInField.kt")
|
||||
public void testReflectOnSuspendLambdaInField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnSuspendLambdaInField.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
|
||||
|
||||
+5
@@ -26408,6 +26408,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
public void testReflectOnLambdaInSuspendLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInSuspendLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("reflectOnSuspendLambdaInField.kt")
|
||||
public void testReflectOnSuspendLambdaInField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnSuspendLambdaInField.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
|
||||
|
||||
+5
@@ -27008,6 +27008,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
public void testReflectOnLambdaInSuspendLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInSuspendLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("reflectOnSuspendLambdaInField.kt")
|
||||
public void testReflectOnSuspendLambdaInField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnSuspendLambdaInField.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
|
||||
|
||||
Reference in New Issue
Block a user