JS backend: detect outer class if used in child local fun.

Fix closure fields when use it from nested functions in method.

(cherry picked from commit 20eea36)
This commit is contained in:
develar
2013-08-08 19:51:49 +04:00
committed by Zalim Bashorov
parent 632d878877
commit b9396ff7e8
2 changed files with 18 additions and 17 deletions
@@ -34,8 +34,6 @@ public final class UsageTracker {
@NotNull @NotNull
private final MemberDescriptor memberDescriptor; private final MemberDescriptor memberDescriptor;
@Nullable
private final UsageTracker parent;
@Nullable @Nullable
private List<UsageTracker> children; private List<UsageTracker> children;
@@ -47,7 +45,6 @@ public final class UsageTracker {
public UsageTracker(@NotNull MemberDescriptor memberDescriptor, @Nullable UsageTracker parent, @Nullable ClassDescriptor trackedClassDescriptor) { public UsageTracker(@NotNull MemberDescriptor memberDescriptor, @Nullable UsageTracker parent, @Nullable ClassDescriptor trackedClassDescriptor) {
this.memberDescriptor = memberDescriptor; this.memberDescriptor = memberDescriptor;
this.trackedClassDescriptor = trackedClassDescriptor; this.trackedClassDescriptor = trackedClassDescriptor;
this.parent = parent;
if (parent != null) { if (parent != null) {
parent.addChild(this); parent.addChild(this);
} }
@@ -119,16 +116,18 @@ public final class UsageTracker {
@Nullable @Nullable
public ClassDescriptor getOuterClassDescriptor() { public ClassDescriptor getOuterClassDescriptor() {
if (outerClassDescriptor == null && parent != null) { if (outerClassDescriptor != null || children == null) {
UsageTracker p = parent; return outerClassDescriptor;
do {
if (p.outerClassDescriptor != null) {
return p.outerClassDescriptor;
}
}
while ((p = p.parent) != null);
} }
return outerClassDescriptor;
for (UsageTracker child : children) {
ClassDescriptor childOuterClassDescriptor = child.getOuterClassDescriptor();
if (childOuterClassDescriptor != null) {
return childOuterClassDescriptor;
}
}
return null;
} }
public void forEachCaptured(Consumer<CallableDescriptor> consumer) { public void forEachCaptured(Consumer<CallableDescriptor> consumer) {
@@ -116,7 +116,9 @@ public class LiteralFunctionTranslator {
if (asInner) { if (asInner) {
addRegularParameters(descriptor, fun, funContext, receiverName); addRegularParameters(descriptor, fun, funContext, receiverName);
if (outerClass != null) { if (outerClass != null) {
if (funContext.usageTracker().isUsed()) { UsageTracker usageTracker = funContext.usageTracker();
assert usageTracker != null;
if (usageTracker.isUsed()) {
return new JsInvocation(rootContext.namer().kotlin("assignOwner"), fun, JsLiteral.THIS); return new JsInvocation(rootContext.namer().kotlin("assignOwner"), fun, JsLiteral.THIS);
} }
else { else {
@@ -159,15 +161,15 @@ public class LiteralFunctionTranslator {
@NotNull ClassTranslator classTranslator) { @NotNull ClassTranslator classTranslator) {
JsFunction fun = createFunction(); JsFunction fun = createFunction();
JsNameRef outerClassRef = fun.getScope().declareName("$this").makeRef(); JsNameRef outerClassRef = fun.getScope().declareName("$this").makeRef();
TranslationContext funContext = rootContext UsageTracker usageTracker = new UsageTracker(descriptor, null, outerClass);
.contextWithScope(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef), new UsageTracker(descriptor, null, TranslationContext funContext = rootContext.contextWithScope(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef),
outerClass)); usageTracker);
fun.getBody().getStatements().add(new JsReturn(classTranslator.translate(funContext))); fun.getBody().getStatements().add(new JsReturn(classTranslator.translate(funContext)));
JetClassBody body = declaration.getBody(); JetClassBody body = declaration.getBody();
assert body != null; assert body != null;
InnerObjectTranslator translator = new InnerObjectTranslator(funContext, fun); InnerObjectTranslator translator = new InnerObjectTranslator(funContext, fun);
return translator.translate(createReference(fun), funContext.usageTracker().isUsed() ? outerClassRef : null); return translator.translate(createReference(fun), usageTracker.isUsed() ? outerClassRef : null);
} }
} }