[JS IR] Initialize enum fields before accessing them in companion object
see https://youtrack.jetbrains.com/issue/KT-43901
This commit is contained in:
Generated
+5
@@ -11090,6 +11090,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
+15
-11
@@ -47,7 +47,7 @@ class EnumUsageLowering(val context: JsCommonBackendContext) : BodyLoweringPass
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun lowerEnumEntry(enumEntry: IrEnumEntry) =
|
private fun lowerEnumEntry(enumEntry: IrEnumEntry) =
|
||||||
enumEntry.getInstanceFun!!.run { JsIrBuilder.buildCall(symbol) }
|
JsIrBuilder.buildCall(enumEntry.getInstanceFun!!.symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ class EnumClassConstructorBodyTransformer(val context: JsCommonBackendContext) :
|
|||||||
|
|
||||||
if (container is IrConstructor) {
|
if (container is IrConstructor) {
|
||||||
|
|
||||||
if (irClass.goodEnum) {
|
if (irClass.isInstantiableEnum) {
|
||||||
// Pass new parameters to delegating constructor calls
|
// Pass new parameters to delegating constructor calls
|
||||||
lowerEnumConstructorsBody(container)
|
lowerEnumConstructorsBody(container)
|
||||||
}
|
}
|
||||||
@@ -278,9 +278,6 @@ class EnumClassConstructorBodyTransformer(val context: JsCommonBackendContext) :
|
|||||||
|
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
|
|
||||||
private val IrClass.goodEnum: Boolean
|
|
||||||
get() = isEnumClass && !isExpect && !isEffectivelyExternal()
|
|
||||||
|
|
||||||
class EnumEntryInstancesLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
class EnumEntryInstancesLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||||
@@ -288,7 +285,7 @@ class EnumEntryInstancesLowering(val context: JsCommonBackendContext) : Declarat
|
|||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (declaration is IrEnumEntry) {
|
if (declaration is IrEnumEntry) {
|
||||||
val irClass = declaration.parentAsClass
|
val irClass = declaration.parentAsClass
|
||||||
if (irClass.goodEnum) {
|
if (irClass.isInstantiableEnum) {
|
||||||
// Create instance variable for each enum entry initialized with `null`
|
// Create instance variable for each enum entry initialized with `null`
|
||||||
return listOf(declaration, createEnumEntryInstanceVariable(irClass, declaration))
|
return listOf(declaration, createEnumEntryInstanceVariable(irClass, declaration))
|
||||||
}
|
}
|
||||||
@@ -322,7 +319,7 @@ class EnumEntryInstancesBodyLowering(val context: JsCommonBackendContext) : Body
|
|||||||
if (container is IrConstructor && container.constructedClass.kind == ClassKind.ENUM_ENTRY) {
|
if (container is IrConstructor && container.constructedClass.kind == ClassKind.ENUM_ENTRY) {
|
||||||
val entryClass = container.constructedClass
|
val entryClass = container.constructedClass
|
||||||
val enum = entryClass.parentAsClass
|
val enum = entryClass.parentAsClass
|
||||||
if (enum.goodEnum) {
|
if (enum.isInstantiableEnum) {
|
||||||
val entry = enum.declarations.filterIsInstance<IrEnumEntry>().find { it.correspondingClass === entryClass }!!
|
val entry = enum.declarations.filterIsInstance<IrEnumEntry>().find { it.correspondingClass === entryClass }!!
|
||||||
|
|
||||||
//In ES6 using `this` before superCall is unavailable, so
|
//In ES6 using `this` before superCall is unavailable, so
|
||||||
@@ -344,7 +341,7 @@ class EnumClassCreateInitializerLowering(val context: JsCommonBackendContext) :
|
|||||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (declaration is IrClass && declaration.goodEnum) {
|
if (declaration is IrClass && declaration.isInstantiableEnum) {
|
||||||
// Create boolean flag that indicates if entry instances were initialized.
|
// Create boolean flag that indicates if entry instances were initialized.
|
||||||
val entryInstancesInitializedVar = createEntryInstancesInitializedVar(declaration)
|
val entryInstancesInitializedVar = createEntryInstancesInitializedVar(declaration)
|
||||||
|
|
||||||
@@ -394,6 +391,10 @@ class EnumClassCreateInitializerLowering(val context: JsCommonBackendContext) :
|
|||||||
+irSetField(null, instanceField, entry.initializerExpression!!.expression.deepCopyWithSymbols(it))
|
+irSetField(null, instanceField, entry.initializerExpression!!.expression.deepCopyWithSymbols(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irClass.companionObject()?.let { companionObject ->
|
||||||
|
+irGetObjectValue(companionObject.defaultType, companionObject.symbol)
|
||||||
|
}
|
||||||
}.statements
|
}.statements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -402,12 +403,12 @@ class EnumClassCreateInitializerLowering(val context: JsCommonBackendContext) :
|
|||||||
class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
private val IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (declaration is IrEnumEntry) {
|
if (declaration is IrEnumEntry) {
|
||||||
val irClass = declaration.parentAsClass
|
val irClass = declaration.parentAsClass
|
||||||
if (irClass.goodEnum) {
|
if (irClass.isInstantiableEnum) {
|
||||||
// Create entry instance getters. These are used to lower `IrGetEnumValue`.
|
// Create entry instance getters. These are used to lower `IrGetEnumValue`.
|
||||||
val entryGetInstanceFun = createGetEntryInstanceFun(irClass, declaration, irClass.initEntryInstancesFun!!)
|
val entryGetInstanceFun = createGetEntryInstanceFun(irClass, declaration, irClass.initEntryInstancesFun!!)
|
||||||
|
|
||||||
@@ -445,6 +446,9 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val IrClass.isInstantiableEnum: Boolean
|
||||||
|
get() = isEnumClass && !isExpect && !isEffectivelyExternal()
|
||||||
|
|
||||||
class EnumSyntheticFunctionsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
class EnumSyntheticFunctionsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun
|
private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun
|
||||||
@@ -454,7 +458,7 @@ class EnumSyntheticFunctionsLowering(val context: JsCommonBackendContext) : Decl
|
|||||||
(declaration.body as? IrSyntheticBody)?.let { body ->
|
(declaration.body as? IrSyntheticBody)?.let { body ->
|
||||||
val kind = body.kind
|
val kind = body.kind
|
||||||
|
|
||||||
declaration.parents.filterIsInstance<IrClass>().firstOrNull { it.goodEnum }?.let { irClass ->
|
declaration.parents.filterIsInstance<IrClass>().firstOrNull { it.isInstantiableEnum }?.let { irClass ->
|
||||||
declaration.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
declaration.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
statements += when (kind) {
|
statements += when (kind) {
|
||||||
IrSyntheticBodyKind.ENUM_VALUES -> createEnumValuesBody(declaration, irClass)
|
IrSyntheticBodyKind.ENUM_VALUES -> createEnumValuesBody(declaration, irClass)
|
||||||
|
|||||||
+2
-3
@@ -12,13 +12,12 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementContainer
|
import org.jetbrains.kotlin.ir.expressions.IrStatementContainer
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.util.companionObject
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
|
||||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
|
||||||
|
|
||||||
class InvokeStaticInitializersLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
class InvokeStaticInitializersLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
if (container !is IrConstructor) return
|
if (container !is IrConstructor) return
|
||||||
|
if (container?.parentClassOrNull?.isEnumClass == true) return
|
||||||
|
|
||||||
val irClass = container.constructedClass
|
val irClass = container.constructedClass
|
||||||
if (irClass.isEffectivelyExternal()) {
|
if (irClass.isEffectivelyExternal()) {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
private var logs = ""
|
||||||
|
|
||||||
|
enum class Foo(val text: String) {
|
||||||
|
FOO("foo"),
|
||||||
|
BAR("bar"),
|
||||||
|
PING("foo");
|
||||||
|
|
||||||
|
init {
|
||||||
|
logs += "${text}A;"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
logs += "StatA;"
|
||||||
|
}
|
||||||
|
val first = values()[0]
|
||||||
|
init {
|
||||||
|
logs += "Stat${first.text};"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
logs += "${text}B;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
Foo.FOO
|
||||||
|
|
||||||
|
if (Foo.first !== Foo.FOO) return "FAIL 0: ${Foo.first}"
|
||||||
|
|
||||||
|
if (logs != "fooA;fooB;barA;barB;fooA;fooB;StatA;Statfoo;") return "FAIL 1: ${logs}"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+5
@@ -11090,6 +11090,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
+5
@@ -11090,6 +11090,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
+5
@@ -11090,6 +11090,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
runTest("compiler/testData/codegen/box/enum/classForEnumEntry.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+5
@@ -9495,6 +9495,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
Generated
+5
@@ -9495,6 +9495,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
Generated
+5
@@ -9495,6 +9495,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+5
@@ -4594,6 +4594,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
runTest("compiler/testData/codegen/box/enum/asReturnExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionAccessingEnumValue.kt")
|
||||||
|
public void testCompanionAccessingEnumValue() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/enum/companionAccessingEnumValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObjectInEnum.kt")
|
@TestMetadata("companionObjectInEnum.kt")
|
||||||
public void testCompanionObjectInEnum() throws Exception {
|
public void testCompanionObjectInEnum() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
runTest("compiler/testData/codegen/box/enum/companionObjectInEnum.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user