diff --git a/compiler/testData/codegen/box/enum/enumCompanionInit.kt b/compiler/testData/codegen/box/enum/enumCompanionInit.kt new file mode 100644 index 00000000000..e45b666ec6f --- /dev/null +++ b/compiler/testData/codegen/box/enum/enumCompanionInit.kt @@ -0,0 +1,46 @@ +var result = "" + +enum class E(a: String) { + X("x"), + Y("y"); + + init { + result += "E.init($a);" + } + + companion object { + init { + result += "E.companion.init;" + val value = E.values()[0].name + result += "$value;" + } + } +} + +enum class F(a: String) { + X("x"), + Y("y"); + + init { + result += "F.init($a);" + } + + companion object { + init { + result += "F.companion.init;" + } + + fun foo() { + result += "F.foo();$X;" + } + } +} + +fun box(): String { + val y = E.Y + result += "${y.name};" + F.foo() + if (result != "E.init(x);E.init(y);E.companion.init;X;Y;F.init(x);F.init(y);F.companion.init;F.foo();X;") return "fail: $result" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/light-analysis/enum/enumCompanionInit.txt b/compiler/testData/codegen/light-analysis/enum/enumCompanionInit.txt new file mode 100644 index 00000000000..8e2dbd024ea --- /dev/null +++ b/compiler/testData/codegen/light-analysis/enum/enumCompanionInit.txt @@ -0,0 +1,42 @@ +@kotlin.Metadata +public enum class E { + public final static field Companion: E.Companion + public final static field X: E + public final static field Y: E + inner class E/Companion + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): void + public static method valueOf(p0: java.lang.String): E + public static method values(): E[] +} + +@kotlin.Metadata +public final static class E/Companion { + inner class E/Companion + private method (): void +} + +@kotlin.Metadata +public final class EnumCompanionInitKt { + private static @org.jetbrains.annotations.NotNull field result: java.lang.String + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static @org.jetbrains.annotations.NotNull method getResult(): java.lang.String + public final static method setResult(@org.jetbrains.annotations.NotNull p0: java.lang.String): void +} + +@kotlin.Metadata +public enum class F { + public final static field Companion: F.Companion + public final static field X: F + public final static field Y: F + inner class F/Companion + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): void + public static method valueOf(p0: java.lang.String): F + public static method values(): F[] +} + +@kotlin.Metadata +public final static class F/Companion { + inner class F/Companion + private method (): void + public final method foo(): void +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 58e570e0f66..25a974b525e 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7319,6 +7319,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("enumCompanionInit.kt") + public void testEnumCompanionInit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/enumCompanionInit.kt"); + doTest(fileName); + } + @TestMetadata("enumInheritedFromTrait.kt") public void testEnumInheritedFromTrait() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/enumInheritedFromTrait.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index f36b03f301c..62ad59aabc1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7319,6 +7319,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("enumCompanionInit.kt") + public void testEnumCompanionInit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/enumCompanionInit.kt"); + doTest(fileName); + } + @TestMetadata("enumInheritedFromTrait.kt") public void testEnumInheritedFromTrait() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/enumInheritedFromTrait.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index df5b352f201..e080416474d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -8154,6 +8154,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("enumCompanionInit.kt") + public void testEnumCompanionInit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/enumCompanionInit.kt"); + doTest(fileName); + } + @TestMetadata("enumInheritedFromTrait.kt") public void testEnumInheritedFromTrait() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/enumInheritedFromTrait.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt index f2cbb7cd14b..8ad8e0553d6 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.isOverridable import org.jetbrains.kotlin.js.backend.ast.JsExpression +import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters import org.jetbrains.kotlin.js.translate.expression.translateFunction @@ -34,8 +35,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty abstract class AbstractDeclarationVisitor : TranslatorVisitor() { override fun emptyResult(context: TranslationContext) { } + open val enumInitializerName: JsName? + get() = null + override fun visitClassOrObject(classOrObject: KtClassOrObject, context: TranslationContext) { - ClassTranslator.translate(classOrObject, context) + ClassTranslator.translate(classOrObject, context, enumInitializerName) val descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), classOrObject) context.export(descriptor) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index 720a9afc901..d92530e7882 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -92,6 +92,12 @@ class ClassTranslator private constructor( constructorFunction.body.statements += bodyVisitor.initializerStatements delegationTranslator.generateDelegated() + val companionDescriptor = descriptor.companionObjectDescriptor + if (enumInitFunction != null && companionDescriptor != null) { + val initInvocation = JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(companionDescriptor), null)) + enumInitFunction.body.statements += JsAstUtils.asSyntheticStatement(initInvocation) + } + translatePrimaryConstructor(constructorFunction, context, delegationTranslator) addMetadataObject() addMetadataType() @@ -446,7 +452,10 @@ class ClassTranslator private constructor( val instanceFun = context().createRootScopedFunction("Instance function: " + descriptor) instanceFun.name = context().getNameForObjectInstance(descriptor) - if (enumInitializerName == null) { + if (enumInitializerName != null) { + instanceFun.body.statements += JsInvocation(pureFqn(enumInitializerName, null)).makeStmt() + } + if (descriptor.kind != ClassKind.ENUM_ENTRY) { val instanceCreatedCondition = JsAstUtils.equality(cachedInstanceName.makeRef(), JsLiteral.NULL) val instanceCreationBlock = JsBlock() val instanceCreatedGuard = JsIf(instanceCreatedCondition, instanceCreationBlock) @@ -455,9 +464,6 @@ class ClassTranslator private constructor( val objectRef = context().getInnerReference(descriptor) instanceCreationBlock.statements += JsNew(objectRef).makeStmt() } - else { - instanceFun.body.statements += JsInvocation(pureFqn(enumInitializerName, null)).makeStmt() - } instanceFun.body.statements += JsReturn(cachedInstanceName.makeRef()) @@ -534,8 +540,8 @@ class ClassTranslator private constructor( } companion object { - @JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext) { - return ClassTranslator(classDeclaration, context, null, null).translate() + @JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext, enumInitializerName: JsName?) { + return ClassTranslator(classDeclaration, context, enumInitializerName, null).translate() } @JvmStatic fun translate(classDeclaration: KtEnumEntry, context: TranslationContext, enumInitializerName: JsName, ordinal: Int) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt index 1e9ed86b5cf..f35e7237357 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt @@ -40,11 +40,14 @@ class DeclarationBodyVisitor( val initializerStatements = mutableListOf() val enumEntries = mutableListOf() + override val enumInitializerName: JsName? + get() = enumInitializer?.name + override fun visitClassOrObject(classOrObject: KtClassOrObject, context: TranslationContext) { super.visitClassOrObject(classOrObject, context) if (classOrObject is KtObjectDeclaration) { - if (classOrObject.isCompanion()) { + if (classOrObject.isCompanion() && containingClass.kind != ClassKind.ENUM_CLASS) { val descriptor = BindingUtils.getDescriptorForElement(context.bindingContext(), classOrObject) as ClassDescriptor addInitializerStatement(JsInvocation(context.getNameForObjectInstance(descriptor).makeRef()).makeStmt()) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index f7f3705cf38..1d17970d2bb 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -604,6 +604,6 @@ public final class ExpressionVisitor extends TranslatorVisitor { ) { JsScope scope = context.getScopeForDescriptor(descriptor); TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor); - ClassTranslator.translate(declaration, classContext); + ClassTranslator.translate(declaration, classContext, null); } }