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:
Shagen Ogandzhanian
2020-12-30 14:52:21 +01:00
parent 7fa04afda2
commit e7dc199ad7
14 changed files with 284 additions and 18 deletions
@@ -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(
@@ -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)
})
)
}
}