diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RegressionTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RegressionTest.java index 827f37f8b38..d958c200eb0 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RegressionTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RegressionTest.java @@ -27,4 +27,8 @@ public final class RegressionTest extends SingleFileTranslationTest { public void testKt2470() throws Exception { checkFooBoxIsOk(); } + + public void testTmpInsidePrimaryConstructor() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 4f31f9dbddb..43d58fd2604 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -129,12 +129,6 @@ public class TranslationContext { return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place); } - @NotNull - public TranslationContext newDeclarationWithScope(@NotNull DeclarationDescriptor descriptor, @NotNull JsScope scope) { - DynamicContext dynamicContext = DynamicContext.newContext(scope, getBlockForDescriptor(descriptor)); - return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, this.getDefinitionPlace()); - } - @NotNull private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) { return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, 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 4db772e4dbc..e4f41a535fc 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 @@ -48,43 +48,58 @@ public final class ClassInitializerTranslator extends AbstractTranslator { private final JetClassOrObject classDeclaration; @NotNull private final List initializerStatements = new SmartList(); + private final JsFunction initFunction; + private final TranslationContext context; public ClassInitializerTranslator( @NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context ) { - super(context.newDeclarationWithScope( - getClassDescriptor(context.bindingContext(), classDeclaration), - new JsFunctionScope(context.scope(), "scope for primary/default constructor"))); + super(context); this.classDeclaration = classDeclaration; + this.initFunction = createInitFunction(classDeclaration, context); + this.context = context.contextWithScope(initFunction); + } + + @NotNull + @Override + protected TranslationContext context() { + return context; + } + + @NotNull + private static JsFunction createInitFunction(JetClassOrObject declaration, TranslationContext context) { + //TODO: it's inconsistent that we have scope for class and function for constructor, currently have problems implementing better way + ClassDescriptor classDescriptor = getClassDescriptor(context.bindingContext(), declaration); + ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); + + if (primaryConstructor != null) { + return context.getFunctionObject(primaryConstructor); + } + else { + return new JsFunction(context.scope(), new JsBlock(), "fake constructor for " + classDescriptor.getName().asString()); + } } @NotNull public JsFunction generateInitializeMethod(DelegationTranslator delegationTranslator) { - //TODO: it's inconsistent that we have scope for class and function for constructor, currently have problems implementing better way ClassDescriptor classDescriptor = getClassDescriptor(bindingContext(), classDeclaration); ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - JsFunction result; if (primaryConstructor != null) { - result = context().getFunctionObject(primaryConstructor); - - result.getBody().getStatements().addAll(setDefaultValueForArguments(primaryConstructor, context())); + initFunction.getBody().getStatements().addAll(setDefaultValueForArguments(primaryConstructor, context())); //NOTE: while we translate constructor parameters we also add property initializer statements // for properties declared as constructor parameters - result.getParameters().addAll(translatePrimaryConstructorParameters()); + initFunction.getParameters().addAll(translatePrimaryConstructorParameters()); - mayBeAddCallToSuperMethod(result); - } - else { - result = new JsFunction(context().scope(), new JsBlock(), "fake constructor for " + classDescriptor.getName().asString()); + mayBeAddCallToSuperMethod(initFunction); } delegationTranslator.addInitCode(initializerStatements); new InitializerVisitor(initializerStatements).traverseContainer(classDeclaration, context()); - List statements = result.getBody().getStatements(); + List statements = initFunction.getBody().getStatements(); for (JsStatement statement : initializerStatements) { if (statement instanceof JsBlock) { @@ -95,7 +110,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator { } } - return result; + return initFunction; } @NotNull diff --git a/js/js.translator/testData/regression/cases/tmpInsidePrimaryConstructor.kt b/js/js.translator/testData/regression/cases/tmpInsidePrimaryConstructor.kt new file mode 100644 index 00000000000..dd4b1092167 --- /dev/null +++ b/js/js.translator/testData/regression/cases/tmpInsidePrimaryConstructor.kt @@ -0,0 +1,37 @@ +package foo + +val x: Int? + get() = null + +// Note: `x ?: 2` expression used to force to create tempary variable + +class A { + val a = x ?: 2 +} + +enum class E(val a: Int = 0) { + X(), + Y() { + val y = x ?: 4 + + override fun value() = y + }, + + val e = x ?: 3 + + open fun value() = e +} + +open class B(val b: Int) + +class C : B(x ?: 6) + + +fun box(): String { + assertEquals(2, A().a) + assertEquals(3, E.X.e) + assertEquals(4, E.Y.value()) + assertEquals(6, C().b) + + return "OK" +}