diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 57a8ea56be4..4316f9ec338 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -415,15 +415,19 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal callInterceptor.interceptEnumEntry(enumEntry) { val enumClass = enumEntry.symbol.owner.parentAsClass val enumEntries = enumClass.declarations.filterIsInstance() - val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall) + val enumInitializer = enumEntry.initializerExpression?.expression + ?: throw InterpreterError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null") + val enumConstructorCall = enumInitializer as? IrEnumConstructorCall + ?: (enumInitializer as IrBlock).statements.filterIsInstance().single() + val enumSuperCall = enumConstructorCall.getSuperEnumCall() val cleanEnumSuperCall = fun() { - enumSuperCall?.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null + enumSuperCall.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null callStack.popState() // result of constructor must be dropped, because next instruction will be `IrGetEnumValue` callStack.dropSubFrame() } - if (enumEntries.isNotEmpty() && enumSuperCall != null) { + if (enumEntries.isNotEmpty()) { val valueArguments = listOf( enumEntry.name.asString().toIrConst(irBuiltIns.stringType), enumEntries.indexOf(enumEntry).toIrConst(irBuiltIns.intType) @@ -431,11 +435,6 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) } } - val enumInitializer = enumEntry.initializerExpression?.expression - ?: throw InterpreterError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null") - val enumConstructorCall = enumInitializer as? IrEnumConstructorCall - ?: (enumInitializer as IrBlock).statements.filterIsInstance().single() - val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass)) environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 03ed3436723..db4250e7d92 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -269,4 +269,14 @@ internal fun IrType.getTypeIfReified(getType: (IrClassifierSymbol) -> IrType): I hasQuestionMark = this.hasQuestionMark || this@getTypeIfReified.hasQuestionMark arguments = newArguments } +} + +internal fun IrFunctionAccessExpression.getSuperEnumCall(): IrEnumConstructorCall { + val name = this.symbol.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() + if (this is IrEnumConstructorCall && name == "kotlin.Enum") return this + return when (val delegatingCall = this.symbol.owner.body?.statements?.get(0)) { + is IrFunctionAccessExpression -> delegatingCall.getSuperEnumCall() + is IrTypeOperatorCall -> (delegatingCall.argument as IrFunctionAccessExpression).getSuperEnumCall() + else -> TODO("$delegatingCall is unexpected") + } } \ No newline at end of file diff --git a/compiler/testData/ir/interpreter/enums2.kt b/compiler/testData/ir/interpreter/enums2.kt index ca376511252..bc0a0e020fc 100644 --- a/compiler/testData/ir/interpreter/enums2.kt +++ b/compiler/testData/ir/interpreter/enums2.kt @@ -24,3 +24,18 @@ const val b3 = Color.RED.getColorAsString() const val c1 = Color.BLACK.getColorAsInt() const val c2 = Color.RED.getColorAsInt() + +@CompileTimeCalculation +enum class EnumWithoutPrimary { + X(), Y(10); + + val someProp: Int + + constructor() : this(0) {} + constructor(value: Int) { + someProp = value + } +} + +const val d1 = EnumWithoutPrimary.X.someProp +const val d2 = EnumWithoutPrimary.Y.someProp