diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 7cc6dc8c61c..f0c6833e054 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -11182,6 +11182,21 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 871a74b222f..a237d12f282 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -304,7 +304,7 @@ private val enumSyntheticFunsLoweringPhase = makeDeclarationTransformerPhase( ::EnumSyntheticFunctionsLowering, name = "EnumSyntheticFunctionsLowering", description = "Implement `valueOf` and `values`", - prerequisite = setOf(enumClassConstructorLoweringPhase) + prerequisite = setOf(enumClassConstructorLoweringPhase, enumClassCreateInitializerLoweringPhase) ) private val enumUsageLoweringPhase = makeBodyLoweringPhase( diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 014d66d10c8..866c60545c1 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -410,7 +410,7 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex val irClass = declaration.parentAsClass if (irClass.isInstantiableEnum) { // Create entry instance getters. These are used to lower `IrGetEnumValue`. - val entryGetInstanceFun = createGetEntryInstanceFun(irClass, declaration, irClass.initEntryInstancesFun!!) + val entryGetInstanceFun = createGetEntryInstanceFun(irClass, declaration) // TODO prettify entryGetInstanceFun.parent = irClass.parent @@ -426,7 +426,7 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex } private fun createGetEntryInstanceFun( - irClass: IrClass, enumEntry: IrEnumEntry, initEntryInstancesFun: IrSimpleFunction + irClass: IrClass, enumEntry: IrEnumEntry ): IrSimpleFunction = context.mapping.enumEntryToGetInstanceFun.getOrPut(enumEntry) { context.irFactory.buildFun { @@ -439,7 +439,7 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex }.also { it.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { statements += context.createIrBuilder(it.symbol).irBlockBody(it) { - +irCall(initEntryInstancesFun) + +irCall(irClass.initEntryInstancesFun!!) +irReturn(irGetField(null, enumEntry.correspondingField!!)) }.statements } @@ -449,20 +449,40 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex private val IrClass.isInstantiableEnum: Boolean get() = isEnumClass && !isExpect && !isEffectivelyExternal() +private val IrDeclaration.parentEnumClassOrNull: IrClass? + get() = parents.filterIsInstance().firstOrNull { it.isInstantiableEnum } + class EnumSyntheticFunctionsLowering(val context: JsCommonBackendContext) : DeclarationTransformer { - private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun + private val IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun + private val IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun override fun transformFlat(declaration: IrDeclaration): List? { + if (declaration is IrConstructor && declaration.isPrimary) { + declaration.parentEnumClassOrNull?.let { enumClass -> + if (declaration.parentClassOrNull?.isCompanion == true) { + (declaration.body as? IrSyntheticBody)?.let { originalBody -> + declaration.parentEnumClassOrNull?.let { enumClass -> + declaration.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { + statements += context.createIrBuilder(declaration.symbol).irBlockBody { + +irCall(enumClass.initEntryInstancesFun!!.symbol) + }.statements + originalBody.statements + } + } + } + } + } + } + if (declaration is IrSimpleFunction) { (declaration.body as? IrSyntheticBody)?.let { body -> val kind = body.kind - declaration.parents.filterIsInstance().firstOrNull { it.isInstantiableEnum }?.let { irClass -> + declaration.parentEnumClassOrNull?.let { enumClass -> declaration.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { statements += when (kind) { - IrSyntheticBodyKind.ENUM_VALUES -> createEnumValuesBody(declaration, irClass) - IrSyntheticBodyKind.ENUM_VALUEOF -> createEnumValueOfBody(declaration, irClass) + IrSyntheticBodyKind.ENUM_VALUES -> createEnumValuesBody(declaration, enumClass) + IrSyntheticBodyKind.ENUM_VALUEOF -> createEnumValueOfBody(declaration, enumClass) }.statements } } @@ -479,15 +499,16 @@ class EnumSyntheticFunctionsLowering(val context: JsCommonBackendContext) : Decl return context.createIrBuilder(valueOfFun.symbol).run { irBlockBody { - +irReturn( - irWhen( - irClass.defaultType, - irClass.enumEntries.map { - irBranch( - irEquals(irString(it.name.identifier), irGet(nameParameter)), irCall(it.getInstanceFun!!) - ) - } + irElseBranch(irCall(throwISESymbol)) - ) + +irWhen( + irClass.defaultType, + irClass.enumEntries.map { + irBranch( + irEquals(irString(it.name.identifier), irGet(nameParameter)), irReturn(irCall(it.getInstanceFun!!)) + ) + } + irElseBranch(irBlock { + +irCall(irClass.initEntryInstancesFun!!) + +irCall(throwISESymbol) + }) ) } } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 68f2e0a271e..2cf8c5ba990 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -154,7 +154,7 @@ private val enumSyntheticFunsLoweringPhase = makeWasmModulePhase( ::EnumSyntheticFunctionsLowering, name = "EnumSyntheticFunctionsLowering", description = "Implement `valueOf` and `values`", - prerequisite = setOf(enumClassConstructorLoweringPhase) + prerequisite = setOf(enumClassConstructorLoweringPhase, enumClassCreateInitializerLoweringPhase) ) private val enumUsageLoweringPhase = makeWasmModulePhase( diff --git a/compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt b/compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt new file mode 100644 index 00000000000..cab7240130a --- /dev/null +++ b/compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt @@ -0,0 +1,53 @@ +// IGNORE_BACKEND: JS +// IGNORE_BACKEND: WASM + +var l = "" + +enum class Foo { + FOO, + BAR; + init { + l += "Foo.$name;" + } + + companion object { + init { + l += "Foo.CO;" + } + + val boo = 22 + } +} + +enum class Foo2 { + FOO, + BAR; + + init { + l += "Foo2.$name;" + } + + companion object { + init { + l += "Foo2.CO;" + } + + val boo = 22 + } +} + +fun box(): String { + try { + Foo.valueOf("NO") + } catch (e: Throwable) { + l += "caught;" + } + + if (l != "Foo.FOO;Foo.BAR;Foo.CO;caught;") return "Failure 0: l = $l" + + l = "" + Foo2.valueOf("BAR") + if (l != "Foo2.FOO;Foo2.BAR;Foo2.CO;") return "Failure 1: l = $l" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/enum/initEntriesInValueOf.kt b/compiler/testData/codegen/box/enum/initEntriesInValueOf.kt new file mode 100644 index 00000000000..cab7240130a --- /dev/null +++ b/compiler/testData/codegen/box/enum/initEntriesInValueOf.kt @@ -0,0 +1,53 @@ +// IGNORE_BACKEND: JS +// IGNORE_BACKEND: WASM + +var l = "" + +enum class Foo { + FOO, + BAR; + init { + l += "Foo.$name;" + } + + companion object { + init { + l += "Foo.CO;" + } + + val boo = 22 + } +} + +enum class Foo2 { + FOO, + BAR; + + init { + l += "Foo2.$name;" + } + + companion object { + init { + l += "Foo2.CO;" + } + + val boo = 22 + } +} + +fun box(): String { + try { + Foo.valueOf("NO") + } catch (e: Throwable) { + l += "caught;" + } + + if (l != "Foo.FOO;Foo.BAR;Foo.CO;caught;") return "Failure 0: l = $l" + + l = "" + Foo2.valueOf("BAR") + if (l != "Foo2.FOO;Foo2.BAR;Foo2.CO;") return "Failure 1: l = $l" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt b/compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt new file mode 100644 index 00000000000..6f9304c62e5 --- /dev/null +++ b/compiler/testData/codegen/box/enum/initEnumAfterObjectAccess.kt @@ -0,0 +1,19 @@ +// IGNORE_BACKEND: JS + +var l = "" +enum class Foo { + F; + init { + l += "Foo;" + } + object L { + init { + l += "Foo.CO;" + } + } +} + +fun box(): String { + Foo.L + return if (l != "Foo.CO;") "FAIL: ${l}" else "OK" +} \ No newline at end of file diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 83b472c9b99..2c81873af7f 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11182,6 +11182,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b3315eddeb7..ddee5d1ad73 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -11182,6 +11182,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 7bb97b8905a..d014cd742ab 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -11182,6 +11182,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 322ade64dc9..8f1efbc235b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -9567,6 +9567,21 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 8655e9f2544..663f2595cbf 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -9567,6 +9567,21 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index c18863bd2ec..edef42e9e5b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -9567,6 +9567,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 6bee512e911..9ee5e2ec75f 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -4651,6 +4651,21 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/enum/inclassobj.kt"); } + @TestMetadata("initEntriesInCompanionObject.kt") + public void testInitEntriesInCompanionObject() throws Exception { + runTest("compiler/testData/codegen/box/enum/initEntriesInCompanionObject.kt"); + } + + @TestMetadata("initEntriesInValueOf.kt") + public void testInitEntriesInValueOf() throws Exception { + 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("inner.kt") public void testInner() throws Exception { runTest("compiler/testData/codegen/box/enum/inner.kt");