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:
pyos
2020-10-08 20:37:21 +02:00
committed by Alexander Udalov
parent 8bc7370b92
commit e6c0575d3a
8 changed files with 47 additions and 13 deletions
@@ -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
@@ -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) {
@@ -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
}
@@ -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"
}
@@ -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")
@@ -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")
@@ -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")