diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumTest.java index 6cb150d8a02..23a3af2e1e6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumTest.java @@ -58,4 +58,8 @@ public class EnumTest extends SingleFileTranslationTest { public void testEquals() throws Exception { checkFooBoxIsOk(); } + + public void testInitializationOrder() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java index cfa31655b8e..9a626770c0e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.js.translate.general.Translation; import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor; import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator; import org.jetbrains.kotlin.js.translate.utils.BindingUtils; +import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.types.KotlinType; @@ -69,14 +70,15 @@ public class DeclarationBodyVisitor extends TranslatorVisitor { @Override public Void visitEnumEntry(@NotNull KtEnumEntry enumEntry, TranslationContext data) { - JsExpression jsEnumEntryCreation; ClassDescriptor descriptor = getClassDescriptor(data.bindingContext(), enumEntry); List supertypes = getSupertypesWithoutFakes(descriptor); if (enumEntry.getBody() != null || supertypes.size() > 1) { enumEntryList.addAll(ClassTranslator.translate(enumEntry, data).getProperties()); } else { assert supertypes.size() == 1 : "Simple Enum entry must have one supertype"; - jsEnumEntryCreation = new ClassInitializerTranslator(enumEntry, data).generateEnumEntryInstanceCreation(supertypes.get(0)); + JsExpression jsEnumEntryCreation = new ClassInitializerTranslator(enumEntry, data) + .generateEnumEntryInstanceCreation(supertypes.get(0)); + jsEnumEntryCreation = TranslationUtils.simpleReturnFunction(data.scope(), jsEnumEntryCreation); enumEntryList.add(new JsPropertyInitializer(data.getNameForDescriptor(descriptor).makeRef(), jsEnumEntryCreation)); } return null; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java index 5910bd49952..41460a74ffb 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java @@ -145,11 +145,15 @@ public final class ClassInitializerTranslator extends AbstractTranslator { private void mayBeAddCallToSuperMethod(JsFunction initializer, @NotNull ClassDescriptor descriptor) { if (classDeclaration.hasModifier(KtTokens.ENUM_KEYWORD)) { addCallToSuperMethod(Collections.emptyList(), initializer); - return; } - if (hasAncestorClass(bindingContext(), classDeclaration)) { + else if (hasAncestorClass(bindingContext(), classDeclaration)) { ResolvedCall superCall = getSuperCall(bindingContext(), classDeclaration); - if (superCall == null) return; + if (superCall == null) { + if (DescriptorUtils.isEnumEntry(descriptor)) { + addCallToSuperMethod(Collections.emptyList(), initializer); + } + return; + } if (classDeclaration instanceof KtEnumEntry) { JsExpression expression = CallTranslator.translate(context(), superCall, null); diff --git a/js/js.translator/testData/enum/cases/initializationOrder.kt b/js/js.translator/testData/enum/cases/initializationOrder.kt new file mode 100644 index 00000000000..626b14d77df --- /dev/null +++ b/js/js.translator/testData/enum/cases/initializationOrder.kt @@ -0,0 +1,33 @@ +package foo + +enum class E { + A, + B { + init { + log("init B") + } + }, + C; + + init { + log("init E") + } +} + +var l = "" +fun log(s: String) { + l += s + ";" +} + +fun box(): String { + log("get Ea.A") + E.A.toString() + log("get E.B") + E.B.toString() + log("get E.C") + E.C.toString() + + if (l != "get Ea.A;init E;init E;init B;init E;get E.B;get E.C;") return "fail: '$l'" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/kotlin_lib_ecma5.js b/js/js.translator/testData/kotlin_lib_ecma5.js index cd6d7e0fd05..3d97e6b1631 100644 --- a/js/js.translator/testData/kotlin_lib_ecma5.js +++ b/js/js.translator/testData/kotlin_lib_ecma5.js @@ -256,27 +256,21 @@ var Kotlin = {}; var values = []; for (var entryName in enumEntryList) { if (enumEntryList.hasOwnProperty(entryName)) { - var entryObject = enumEntryList[entryName]; + var entryFactory = enumEntryList[entryName]; values.push(entryName); - if (typeof entryObject === 'function' && entryObject.type === Kotlin.TYPE.INIT_FUN) { - entryObject.className = entryName; - Object.defineProperty(cls, entryName, { - get: function(ordinal, name, obj) { - return function() { - var result = obj.apply(this); - result.ordinal$ = ordinal; - result.name$ = name; - return result; - } - }(i++, entryName, entryObject), - configurable: true - }) + + var entryObject; + if (typeof entryFactory === 'function' && entryFactory.type === Kotlin.TYPE.INIT_FUN) { + entryFactory.className = entryName; + entryObject = entryFactory.apply(cls); } else { - entryObject.ordinal$ = i++; - entryObject.name$ = entryName; - cls[entryName] = entryObject; + entryObject = entryFactory(); } + + entryObject.ordinal$ = i++; + entryObject.name$ = entryName; + cls[entryName] = entryObject; } } cls.valuesNames$ = values;