[JS IR & WASM] Fix executing init blocks for enums with nested objects

This commit is contained in:
Sergej Jaskiewicz
2021-10-13 17:06:32 +03:00
committed by Space
parent 8e0e2fe52c
commit 9e5520bba8
11 changed files with 164 additions and 34 deletions
@@ -755,7 +755,8 @@ private val staticMembersLoweringPhase = makeDeclarationTransformerPhase(
private val objectDeclarationLoweringPhase = makeDeclarationTransformerPhase(
::ObjectDeclarationLowering,
name = "ObjectDeclarationLowering",
description = "Create lazy object instance generator functions"
description = "Create lazy object instance generator functions",
prerequisite = setOf(enumClassCreateInitializerLoweringPhase)
)
private val invokeStaticInitializersPhase = makeBodyLoweringPhase(
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ObjectDeclarationLowering(
val context: JsCommonBackendContext
@@ -34,6 +35,11 @@ class ObjectDeclarationLowering(
private var IrClass.instanceField by context.mapping.objectToInstanceField
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
/**
* If the object being lowered is nested inside an enum class, we want to also initialize the enum entries when initializing the object.
*/
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
return null
@@ -54,8 +60,12 @@ class ObjectDeclarationLowering(
val primaryConstructor = declaration.primaryConstructor ?: declaration.syntheticPrimaryConstructor!!
val initEntryInstancesFun = declaration.parent.safeAs<IrClass>()?.initEntryInstancesFun
getInstanceFun.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements += context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) {
if (initEntryInstancesFun != null)
+irCall(initEntryInstancesFun)
+irIfThen(
irEqualsNull(irGetField(null, instanceField)),
// Instance field initialized inside constructor
@@ -421,7 +421,8 @@ private val builtInsLoweringPhase = makeWasmModulePhase(
private val objectDeclarationLoweringPhase = makeWasmModulePhase(
::ObjectDeclarationLowering,
name = "ObjectDeclarationLowering",
description = "Create lazy object instance generator functions"
description = "Create lazy object instance generator functions",
prerequisite = setOf(enumClassCreateInitializerLoweringPhase)
)
private val objectUsageLoweringPhase = makeWasmModulePhase(
+27 -6
View File
@@ -1,7 +1,7 @@
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: IGNORED_IN_JS
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// DONT_TARGET_EXACT_BACKEND: JS
// DONT_TARGET_EXACT_BACKEND: JS_IR
// DONT_TARGET_EXACT_BACKEND: JS_IR_ES6
// DONT_TARGET_EXACT_BACKEND: WASM
// IGNORE_BACKEND: NATIVE
var result = ""
@@ -41,11 +41,32 @@ enum class F(a: String) {
}
}
enum class G(a: String) {
X("x"),
Y("y");
init {
result += "G.init($a);"
}
object O {
init {
result += "G.O.init;"
}
fun foo() {
result += "G.O.foo();$X;"
}
}
}
fun box(): String {
val y = E.Y
result += "${y.name};"
F.foo()
if (result != "E.init(x);E.init(y);E.companion.init;X;Y;F.init(x);F.init(y);F.companion.init;F.foo();X;") return "fail: $result"
G.O.foo()
if (result != "E.init(x);E.init(y);E.companion.init;X;Y;F.init(x);F.init(y);F.companion.init;F.foo();X;G.O.init;G.O.foo();X;")
return "fail: $result"
return "OK"
}
}
@@ -0,0 +1,72 @@
// TARGET_BACKEND: JS
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: JS_IR_ES6
// TARGET_BACKEND: WASM
// WITH_RUNTIME
var result = ""
enum class E(a: String) {
X("x"),
Y("y");
init {
result += "E.init($a);"
}
companion object {
init {
result += "E.companion.init;"
val value = E.values()[0].name
result += "$value;"
}
}
}
enum class F(a: String) {
X("x"),
Y("y");
init {
result += "F.init($a);"
}
companion object {
init {
result += "F.companion.init;"
}
fun foo() {
result += "F.foo();$X;"
}
}
}
enum class G(a: String) {
X("x"),
Y("y");
init {
result += "G.init($a);"
}
object O {
init {
result += "G.O.init;"
}
fun foo() {
result += "G.O.foo();$X;"
}
}
}
fun box(): String {
val y = E.Y
result += "${y.name};"
F.foo()
G.O.foo()
if (result != "E.init(x);E.init(y);E.companion.init;X;Y;F.init(x);F.init(y);F.companion.init;F.foo();X;G.init(x);G.init(y);G.O.init;G.O.foo();X;")
return "fail: $result"
return "OK"
}
@@ -1,4 +1,7 @@
// IGNORE_BACKEND: JS
// DONT_TARGET_EXACT_BACKEND: JS
// DONT_TARGET_EXACT_BACKEND: JS_IR
// DONT_TARGET_EXACT_BACKEND: JS_IR_ES6
// DONT_TARGET_EXACT_BACKEND: WASM
var l = ""
enum class Foo {
@@ -16,4 +19,4 @@ enum class Foo {
fun box(): String {
Foo.L
return if (l != "Foo.CO;") "FAIL: ${l}" else "OK"
}
}
@@ -0,0 +1,22 @@
// TARGET_BACKEND: JS
// TARGET_BACKEND: JS_IR
// TARGET_BACKEND: JS_IR_ES6
// TARGET_BACKEND: WASM
var l = ""
enum class Foo {
F;
init {
l += "Foo;"
}
object L {
init {
l += "Foo.CO;"
}
}
}
fun box(): String {
Foo.L
return if (l != "Foo;Foo.CO;") "FAIL: ${l}" else "OK"
}
@@ -10991,9 +10991,9 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/enum/emptyEnumValuesValueOf.kt");
}
@TestMetadata("enumCompanionInit.kt")
public void testEnumCompanionInit() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInit.kt");
@TestMetadata("enumCompanionInitJsAndWasm.kt")
public void testEnumCompanionInitJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInitJsAndWasm.kt");
}
@TestMetadata("enumConstructorParameterClashWithDefaults.kt")
@@ -11076,9 +11076,9 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/enum/initEntriesInValueOf.kt");
}
@TestMetadata("initEnumAfterObjectAccess.kt")
public void testInitEnumAfterObjectAccess() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt");
@TestMetadata("initEnumAfterObjectAccessJsAndWasm.kt")
public void testInitEnumAfterObjectAccessJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccessJsAndWasm.kt");
}
@TestMetadata("inner.kt")
@@ -10397,9 +10397,9 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/enum/emptyEnumValuesValueOf.kt");
}
@TestMetadata("enumCompanionInit.kt")
public void testEnumCompanionInit() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInit.kt");
@TestMetadata("enumCompanionInitJsAndWasm.kt")
public void testEnumCompanionInitJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInitJsAndWasm.kt");
}
@TestMetadata("enumConstructorParameterClashWithDefaults.kt")
@@ -10482,9 +10482,9 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/enum/initEntriesInValueOf.kt");
}
@TestMetadata("initEnumAfterObjectAccess.kt")
public void testInitEnumAfterObjectAccess() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt");
@TestMetadata("initEnumAfterObjectAccessJsAndWasm.kt")
public void testInitEnumAfterObjectAccessJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccessJsAndWasm.kt");
}
@TestMetadata("inner.kt")
@@ -10362,9 +10362,9 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/enum/emptyEnumValuesValueOf.kt");
}
@TestMetadata("enumCompanionInit.kt")
public void testEnumCompanionInit() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInit.kt");
@TestMetadata("enumCompanionInitJsAndWasm.kt")
public void testEnumCompanionInitJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInitJsAndWasm.kt");
}
@TestMetadata("enumConstructorParameterClashWithDefaults.kt")
@@ -10447,9 +10447,9 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/enum/initEntriesInValueOf.kt");
}
@TestMetadata("initEnumAfterObjectAccess.kt")
public void testInitEnumAfterObjectAccess() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt");
@TestMetadata("initEnumAfterObjectAccessJsAndWasm.kt")
public void testInitEnumAfterObjectAccessJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccessJsAndWasm.kt");
}
@TestMetadata("inner.kt")
@@ -9658,9 +9658,9 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/enum/emptyEnumValuesValueOf.kt");
}
@TestMetadata("enumCompanionInit.kt")
public void testEnumCompanionInit() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInit.kt");
@TestMetadata("enumCompanionInitJsAndWasm.kt")
public void testEnumCompanionInitJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/enumCompanionInitJsAndWasm.kt");
}
@TestMetadata("enumConstructorParameterClashWithDefaults.kt")
@@ -9743,9 +9743,9 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/enum/initEntriesInValueOf.kt");
}
@TestMetadata("initEnumAfterObjectAccess.kt")
public void testInitEnumAfterObjectAccess() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt");
@TestMetadata("initEnumAfterObjectAccessJsAndWasm.kt")
public void testInitEnumAfterObjectAccessJsAndWasm() throws Exception {
runTest("compiler/testData/codegen/box/enum/initEnumAfterObjectAccessJsAndWasm.kt");
}
@TestMetadata("inner.kt")