JS backend: fix missed variable declarations for tmps in class primary/default constructor
#KT-7864 Fixed
This commit is contained in:
@@ -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);
|
||||
|
||||
+30
-15
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user