JS backend: fix missed variable declarations for tmps in class primary/default constructor

#KT-7864 Fixed
This commit is contained in:
Zalim Bashorov
2015-05-29 17:35:05 +03:00
parent e0f819d93c
commit f1d37572c8
4 changed files with 71 additions and 21 deletions
@@ -27,4 +27,8 @@ public final class RegressionTest extends SingleFileTranslationTest {
public void testKt2470() throws Exception {
checkFooBoxIsOk();
}
public void testTmpInsidePrimaryConstructor() throws Exception {
checkFooBoxIsOk();
}
}
@@ -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);
@@ -48,43 +48,58 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
private final JetClassOrObject classDeclaration;
@NotNull
private final List<JsStatement> initializerStatements = new SmartList<JsStatement>();
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<JsStatement> statements = result.getBody().getStatements();
List<JsStatement> 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
@@ -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"
}