Init enum entries whenever we access companion object or accessing valueOf
Fixes https://youtrack.jetbrains.com/issue/KT-43987 Fixes https://youtrack.jetbrains.com/issue/KT-43989
This commit is contained in:
Generated
+15
@@ -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");
|
||||
|
||||
@@ -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(
|
||||
|
||||
+37
-16
@@ -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<IrClass>().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<IrDeclaration>? {
|
||||
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<IrClass>().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)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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(
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
+15
@@ -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");
|
||||
|
||||
+15
@@ -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");
|
||||
|
||||
+15
@@ -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");
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+15
@@ -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");
|
||||
|
||||
Generated
+15
@@ -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");
|
||||
|
||||
Generated
+15
@@ -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");
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+15
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user