[K/JS, K/N, K/Wasm] Fix more general case of the ^KT-61929 issue
This commit is contained in:
+25
-3
@@ -72,7 +72,8 @@ class LocalDeclarationsLowering(
|
|||||||
val suggestUniqueNames: Boolean = true, // When `true` appends a `$#index` suffix to lifted declaration names
|
val suggestUniqueNames: Boolean = true, // When `true` appends a `$#index` suffix to lifted declaration names
|
||||||
val compatibilityModeForInlinedLocalDelegatedPropertyAccessors: Boolean = false, // Keep old names because of KT-49030
|
val compatibilityModeForInlinedLocalDelegatedPropertyAccessors: Boolean = false, // Keep old names because of KT-49030
|
||||||
val forceFieldsForInlineCaptures: Boolean = false, // See `LocalClassContext`
|
val forceFieldsForInlineCaptures: Boolean = false, // See `LocalClassContext`
|
||||||
private val postLocalDeclarationLoweringCallback: ((IntermediateDatastructures) -> Unit)? = null
|
private val postLocalDeclarationLoweringCallback: ((IntermediateDatastructures) -> Unit)? = null,
|
||||||
|
private val getConstructorsThatCouldCaptureParamsWithoutFieldCreating: IrClass.() -> Iterable<IrConstructor> = { listOfNotNull(primaryConstructor) }
|
||||||
) :
|
) :
|
||||||
BodyLoweringPass {
|
BodyLoweringPass {
|
||||||
|
|
||||||
@@ -338,6 +339,16 @@ class LocalDeclarationsLowering(
|
|||||||
visitMember(declaration) ?: super.visitFunction(declaration)
|
visitMember(declaration) ?: super.visitFunction(declaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement =
|
||||||
|
visitWithTheSingleConstructorContext(declaration)
|
||||||
|
?: visitMember(declaration)
|
||||||
|
?: super.visitAnonymousInitializer(declaration)
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField): IrStatement =
|
||||||
|
visitWithTheSingleConstructorContext(declaration)
|
||||||
|
?: visitMember(declaration)
|
||||||
|
?: super.visitField(declaration)
|
||||||
|
|
||||||
private fun visitMember(declaration: IrDeclaration): IrStatement? =
|
private fun visitMember(declaration: IrDeclaration): IrStatement? =
|
||||||
if (localContext is LocalClassContext && declaration.parent == localContext.declaration) {
|
if (localContext is LocalClassContext && declaration.parent == localContext.declaration) {
|
||||||
val classMemberLocalContext = LocalClassMemberContext(declaration, localContext)
|
val classMemberLocalContext = LocalClassMemberContext(declaration, localContext)
|
||||||
@@ -346,6 +357,15 @@ class LocalDeclarationsLowering(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun visitWithTheSingleConstructorContext(declaration: IrDeclaration): IrStatement? {
|
||||||
|
return if (localContext is LocalClassContext && declaration.parent == localContext.declaration) {
|
||||||
|
val constructorContext = localContext.constructorContext ?: return null
|
||||||
|
declaration.apply { transformChildrenVoid(FunctionBodiesRewriter(constructorContext)) }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
||||||
// Body is transformed separately. See loop over constructors in rewriteDeclarations().
|
// Body is transformed separately. See loop over constructors in rewriteDeclarations().
|
||||||
|
|
||||||
@@ -1057,8 +1077,10 @@ class LocalDeclarationsLowering(
|
|||||||
// TODO: this should ideally run after initializers are added to constructors, but that'd place
|
// TODO: this should ideally run after initializers are added to constructors, but that'd place
|
||||||
// other restrictions on IR (e.g. after the initializers are moved you can no longer create fields
|
// other restrictions on IR (e.g. after the initializers are moved you can no longer create fields
|
||||||
// with initializers) which makes that hard to implement.
|
// with initializers) which makes that hard to implement.
|
||||||
val constructorContext = declaration.constructors.mapNotNull { localClassConstructors[it] }
|
val constructorContext = declaration.getConstructorsThatCouldCaptureParamsWithoutFieldCreating()
|
||||||
.singleOrNull { it.declaration.delegationKind(context.irBuiltIns) == ConstructorDelegationKind.CALLS_SUPER }
|
.mapNotNull { localClassConstructors[it] }
|
||||||
|
.singleOrNull()
|
||||||
|
|
||||||
localClasses[declaration] = LocalClassContext(declaration, data.inInlineFunctionScope, constructorContext)
|
localClasses[declaration] = LocalClassContext(declaration, data.inInlineFunctionScope, constructorContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
|||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.name.NameUtils
|
import org.jetbrains.kotlin.name.NameUtils
|
||||||
|
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
|
||||||
|
|
||||||
private var patchParentPhases = 0
|
private var patchParentPhases = 0
|
||||||
|
|
||||||
@@ -154,6 +155,9 @@ internal val localDeclarationsPhase = makeIrFilePhase(
|
|||||||
JvmVisibilityPolicy(),
|
JvmVisibilityPolicy(),
|
||||||
compatibilityModeForInlinedLocalDelegatedPropertyAccessors = true,
|
compatibilityModeForInlinedLocalDelegatedPropertyAccessors = true,
|
||||||
forceFieldsForInlineCaptures = true,
|
forceFieldsForInlineCaptures = true,
|
||||||
|
getConstructorsThatCouldCaptureParamsWithoutFieldCreating = {
|
||||||
|
declarations.filterIsInstanceAnd<IrConstructor> { it.delegationKind(context.irBuiltIns) == ConstructorDelegationKind.CALLS_SUPER }
|
||||||
|
},
|
||||||
postLocalDeclarationLoweringCallback = context.localDeclarationsLoweringData?.let {
|
postLocalDeclarationLoweringCallback = context.localDeclarationsLoweringData?.let {
|
||||||
{ data ->
|
{ data ->
|
||||||
data.localFunctions.forEach { (localFunction, localContext) ->
|
data.localFunctions.forEach { (localFunction, localContext) ->
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
// KT-61929
|
// KT-61929
|
||||||
// WITH_SDTLIB
|
// WITH_SDTLIB
|
||||||
|
// IGNORE_BACKEND: JVM
|
||||||
// EXPECTED_REACHABLE_NODES: 1301
|
// EXPECTED_REACHABLE_NODES: 1301
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
fun doSomething(lambda: () -> Unit) { lambda() }
|
fun doSomething(lambda: () -> Unit) { lambda() }
|
||||||
|
|
||||||
class CompilerBug(result: String) {
|
class CompilerBug1(result: String) {
|
||||||
var result: String = "Failed"
|
var result: String = "Failed"
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -23,6 +24,62 @@ class CompilerBug(result: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
class CompilerBug2(result: String) {
|
||||||
return CompilerBug("OK").result
|
var result: String = "Fail"
|
||||||
|
|
||||||
|
init {
|
||||||
|
run {
|
||||||
|
class Foo {
|
||||||
|
init {
|
||||||
|
doSomething { completed(result) }
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun completed(value: String) {
|
||||||
|
this.result = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompilerBug3(result: String) {
|
||||||
|
var result: String = "OK"
|
||||||
|
|
||||||
|
init {
|
||||||
|
run {
|
||||||
|
class Foo {
|
||||||
|
init {
|
||||||
|
doSomething { completed(result) }
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
constructor(test: String) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.result == "OK") {
|
||||||
|
this.result = "Failed with the empty constructor"
|
||||||
|
Foo()
|
||||||
|
}
|
||||||
|
if (this.result == "OK") {
|
||||||
|
this.result = "Failed with one parameter constructor"
|
||||||
|
Foo("Test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun completed(value: String) {
|
||||||
|
this.result = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
CompilerBug1("OK").result.also { if (it != "OK") return "CompilerBug1: $it" }
|
||||||
|
CompilerBug2("OK").result.also { if (it != "OK") return "CompilerBug2: $it" }
|
||||||
|
CompilerBug3("OK").result.also { if (it != "OK") return "CompilerBug3: $it" }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
-1
@@ -40,7 +40,6 @@ public interface test/Z {
|
|||||||
public final class test/_1Kt$test$1 {
|
public final class test/_1Kt$test$1 {
|
||||||
// source: '1.kt'
|
// source: '1.kt'
|
||||||
enclosing method test/_1Kt.test(Lkotlin/jvm/functions/Function0;)Ltest/Z;
|
enclosing method test/_1Kt.test(Lkotlin/jvm/functions/Function0;)Ltest/Z;
|
||||||
synthetic final field $z: kotlin.jvm.functions.Function0
|
|
||||||
private final field p: java.lang.String
|
private final field p: java.lang.String
|
||||||
inner (anonymous) class test/_1Kt$test$1
|
inner (anonymous) class test/_1Kt$test$1
|
||||||
public method <init>(p0: kotlin.jvm.functions.Function0): void
|
public method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||||
|
|||||||
-1
@@ -40,7 +40,6 @@ public interface test/Z {
|
|||||||
public final class test/_1Kt$test$1 {
|
public final class test/_1Kt$test$1 {
|
||||||
// source: '1.kt'
|
// source: '1.kt'
|
||||||
enclosing method test/_1Kt.test(Lkotlin/jvm/functions/Function0;)Ltest/Z;
|
enclosing method test/_1Kt.test(Lkotlin/jvm/functions/Function0;)Ltest/Z;
|
||||||
synthetic final field $z: kotlin.jvm.functions.Function0
|
|
||||||
private final field p: java.lang.String
|
private final field p: java.lang.String
|
||||||
inner (anonymous) class test/_1Kt$test$1
|
inner (anonymous) class test/_1Kt$test$1
|
||||||
public method <init>(p0: kotlin.jvm.functions.Function0): void
|
public method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||||
|
|||||||
Reference in New Issue
Block a user