diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt index dbf1fecbf1d..293166ee7df 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt @@ -146,39 +146,65 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context: private fun generateSuperConstructorCall(irBlockBody: IrBlockBodyImpl, ktClassOrObject: KtClassOrObject) { val classDescriptor = getOrFail(BindingContext.CLASS, ktClassOrObject) - if (classDescriptor.kind == ClassKind.ENUM_CLASS) { - val kotlinEnumConstructor = context.builtIns.enum.unsubstitutedPrimaryConstructor!! - irBlockBody.addStatement(IrEnumConstructorCallImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, kotlinEnumConstructor)) - return - } - - val ktSuperTypeList = ktClassOrObject.getSuperTypeList() ?: return - for (ktSuperTypeListEntry in ktSuperTypeList.entries) { - if (ktSuperTypeListEntry is KtSuperTypeCallEntry) { - val statementGenerator = createStatementGenerator() - val superConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktSuperTypeListEntry)!!) - val irSuperConstructorCall = CallGenerator(statementGenerator).generateCall( - ktSuperTypeListEntry, superConstructorCall, IrOperator.SUPER_CONSTRUCTOR_CALL) - irBlockBody.addStatement(irSuperConstructorCall) + when (classDescriptor.kind) { + ClassKind.ENUM_CLASS -> { + val kotlinEnumConstructor = context.builtIns.enum.unsubstitutedPrimaryConstructor!! + irBlockBody.addStatement(IrEnumConstructorCallImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, + kotlinEnumConstructor, null)) + } + ClassKind.ENUM_ENTRY -> { + irBlockBody.addStatement(generateEnumEntrySuperConstructorCall(ktClassOrObject as KtEnumEntry, classDescriptor)) + } + else -> { + val ktSuperTypeList = ktClassOrObject.getSuperTypeList() ?: return + for (ktSuperTypeListEntry in ktSuperTypeList.entries) { + if (ktSuperTypeListEntry is KtSuperTypeCallEntry) { + val statementGenerator = createStatementGenerator() + val superConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktSuperTypeListEntry)!!) + val irSuperConstructorCall = CallGenerator(statementGenerator).generateCall( + ktSuperTypeListEntry, superConstructorCall, IrOperator.SUPER_CONSTRUCTOR_CALL) + irBlockBody.addStatement(irSuperConstructorCall) + } + } } } } + private fun generateEnumEntrySuperConstructorCall(ktEnumEntry: KtEnumEntry, enumEntryDescriptor: ClassDescriptor): IrExpression { + return generateEnumConstructorCallOrSuperCall(ktEnumEntry, enumEntryDescriptor.containingDeclaration as ClassDescriptor, null) + } + fun generateEnumEntryInitializer(ktEnumEntry: KtEnumEntry, enumEntryDescriptor: ClassDescriptor): IrExpression { + // Enum entry with body has a corresponding underlying class + if (ktEnumEntry.getBody() != null) { + val enumEntryConstructor = enumEntryDescriptor.unsubstitutedPrimaryConstructor!! + return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, + enumEntryConstructor, enumEntryDescriptor) + } + + return generateEnumConstructorCallOrSuperCall(ktEnumEntry, enumEntryDescriptor.containingDeclaration as ClassDescriptor, enumEntryDescriptor) + } + + private fun generateEnumConstructorCallOrSuperCall( + ktEnumEntry: KtEnumEntry, + enumClassDescriptor: ClassDescriptor, + enumEntryOrNull: ClassDescriptor? + ): IrExpression { val statementGenerator = createStatementGenerator() - val ktSuperCallElement = ktEnumEntry.getSuperTypeListEntries().firstOrNull() - - if (ktSuperCallElement != null) { + // Entry constructor with argument(s) + ktEnumEntry.getSuperTypeListEntries().firstOrNull()?.let { ktSuperCallElement -> val enumConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktSuperCallElement)!!) return CallGenerator(statementGenerator).generateEnumConstructorSuperCall( - ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumConstructorCall, enumEntryDescriptor) + ktEnumEntry.startOffset, ktEnumEntry.endOffset, + enumConstructorCall, enumEntryOrNull) + } // No-argument enum entry constructor - val enumClassDescriptor = enumEntryDescriptor.containingDeclaration as ClassDescriptor val enumClassConstructor = enumClassDescriptor.unsubstitutedPrimaryConstructor!! - return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumClassConstructor, enumEntryDescriptor) + return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, + enumClassConstructor, enumEntryOrNull) } fun generateNestedInitializersBody(ktClassOrObject: KtClassOrObject): IrBody { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 0ed60b116a8..5399a2795b6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -56,7 +56,8 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE } } - fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder, enumEntryDescriptor: ClassDescriptor) : IrExpression { + fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder, + enumEntryDescriptor: ClassDescriptor?) : IrExpression { val constructorDescriptor = call.descriptor if (constructorDescriptor !is ConstructorDescriptor) throw AssertionError("Constructor expected: $constructorDescriptor") val classDescriptor = constructorDescriptor.containingDeclaration diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt index 0335faf2c55..f8d6049759a 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt @@ -111,8 +111,8 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator BodyGenerator(enumEntryDescriptor.containingDeclaration, context) .generateEnumEntryInitializer(ktEnumEntry, enumEntryDescriptor) - ktEnumEntry.getBody()?.let { ktEnumEntryBody -> - // TODO + if (ktEnumEntry.getBody() != null) { + irEnumEntry.correspondingClass = generateClass(ktEnumEntry) } return irEnumEntry diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt index a777c736258..60e0e9bfcb3 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt @@ -43,6 +43,7 @@ enum class IrDeclarationKind { enum class IrDeclarationOrigin { DEFINED, + CLASS_FOR_ENUM_ENTRY, GENERATED_DATA_CLASS_MEMBER, LOCAL_FUNCTION_FOR_LAMBDA, IR_TEMPORARY_VARIABLE, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrEnumConstructorCall.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrEnumConstructorCall.kt index 7a344288884..b314aed6f94 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrEnumConstructorCall.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrEnumConstructorCall.kt @@ -26,7 +26,7 @@ interface IrEnumConstructorCall : IrGeneralCall { val enumEntryDescriptor: ClassDescriptor? } -val IrEnumConstructorCall.isDelegating: Boolean +val IrEnumConstructorCall.isSuper: Boolean get() = enumEntryDescriptor == null class IrEnumConstructorCallImpl( diff --git a/compiler/testData/ir/irText/classes/enum.kt b/compiler/testData/ir/irText/classes/enum.kt index 233fef8f5c8..97f26f6b250 100644 --- a/compiler/testData/ir/irText/classes/enum.kt +++ b/compiler/testData/ir/irText/classes/enum.kt @@ -6,4 +6,33 @@ enum class TestEnum2(val x: Int) { TEST1(1), TEST2(2), TEST3(3) +} + +enum class TestEnum3 { + TEST { + override fun foo() { + println("Hello, world!") + } + } + ; + abstract fun foo() +} + +enum class TestEnum4(val x: Int) { + TEST1(1) { + override fun foo() { + println(TEST1) + } + }, + TEST2(2) { + val z: Int + init { + z = x + } + override fun foo() { + println(TEST2) + } + } + ; + abstract fun foo() } \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/enum.txt b/compiler/testData/ir/irText/classes/enum.txt index a290321b1f2..4c217290b97 100644 --- a/compiler/testData/ir/irText/classes/enum.txt +++ b/compiler/testData/ir/irText/classes/enum.txt @@ -25,3 +25,55 @@ FILE /enum.kt ENUM_ENTRY enum entry TEST3 init: ENUM_CONSTRUCTOR_CALL TestEnum2 TEST3 x: CONST Int type=kotlin.Int value='3' + CLASS ENUM_CLASS TestEnum3 + FUN private constructor TestEnum3() + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL Enum super + ENUM_ENTRY enum entry TEST + init: ENUM_CONSTRUCTOR_CALL TEST TEST + class: CLASS ENUM_ENTRY TEST + FUN private constructor TEST() + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL TestEnum3 super + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .println type=kotlin.Unit operator=null + message: CONST String type=kotlin.String value='Hello, world!' + FUN public abstract fun foo(): kotlin.Unit + CLASS ENUM_CLASS TestEnum4 + FUN private constructor TestEnum4(/*0*/ x: kotlin.Int) + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL Enum super + SET_BACKING_FIELD x type=kotlin.Unit operator=null + GET_VAR x type=kotlin.Int operator=INITIALIZE_PROPERTY_FROM_PARAMETER + PROPERTY public final val x: kotlin.Int + EXPRESSION_BODY + GET_VAR x type=kotlin.Int operator=INITIALIZE_PROPERTY_FROM_PARAMETER + ENUM_ENTRY enum entry TEST1 + init: ENUM_CONSTRUCTOR_CALL TEST1 TEST1 + class: CLASS ENUM_ENTRY TEST1 + FUN private constructor TEST1() + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL TestEnum4 super + x: CONST Int type=kotlin.Int value='1' + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .println type=kotlin.Unit operator=null + message: GET_ENUM_VALUE TEST1 type=TestEnum4 + ENUM_ENTRY enum entry TEST2 + init: ENUM_CONSTRUCTOR_CALL TEST2 TEST2 + class: CLASS ENUM_ENTRY TEST2 + FUN private constructor TEST2() + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL TestEnum4 super + x: CONST Int type=kotlin.Int value='2' + BLOCK type=kotlin.Unit operator=null + SET_BACKING_FIELD z type=kotlin.Unit operator=null + CALL . type=kotlin.Int operator=GET_PROPERTY + $this: THIS enum entry TEST2 type=TestEnum4.TEST2 + PROPERTY public final val z: kotlin.Int + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .println type=kotlin.Unit operator=null + message: GET_ENUM_VALUE TEST2 type=TestEnum4 + FUN public abstract fun foo(): kotlin.Unit