diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java index e339c280616..46aaaab3489 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java @@ -31,8 +31,11 @@ public final class ClosureTest extends SingleFileTranslationTest { fooBoxTest(); } - public void testLocalParameterInCallback() throws Exception { fooBoxTest(); } + + public void testClosureReferencingMember() throws Exception { + fooBoxTest(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java index ef0f175d5db..7a343078b0b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java @@ -31,10 +31,13 @@ public final class TemporaryVariable { private final JsExpression assignmentExpression; @NotNull private final JsName variableName; + @NotNull + private final JsExpression initExpression; /*package*/ TemporaryVariable(@NotNull JsName temporaryName, @NotNull JsExpression initExpression) { this.variableName = temporaryName; - this.assignmentExpression = AstUtil.newAssignment(variableName.makeRef(), initExpression); + this.initExpression = initExpression; + this.assignmentExpression = AstUtil.newAssignment(variableName.makeRef(), this.initExpression); } @NotNull @@ -51,4 +54,9 @@ public final class TemporaryVariable { public JsExpression assignmentExpression() { return assignmentExpression; } + + @NotNull + public JsExpression initExpression() { + return initExpression; + } } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java index a25486beab3..e5c536b0b99 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java @@ -40,9 +40,9 @@ import java.util.ArrayList; import java.util.List; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; import static org.jetbrains.k2js.translate.utils.FunctionBodyTranslator.translateFunctionBody; import static org.jetbrains.k2js.translate.utils.JsAstUtils.setParameters; +import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; /** @@ -52,7 +52,7 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull public static FunctionTranslator newInstance(@NotNull JetDeclarationWithBody function, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { return new FunctionTranslator(function, context); } @@ -73,7 +73,7 @@ public final class FunctionTranslator extends AbstractTranslator { private final JsBlock functionBody; private FunctionTranslator(@NotNull JetDeclarationWithBody functionDeclaration, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { super(context); this.descriptor = getFunctionDescriptor(context.bindingContext(), functionDeclaration); this.functionDeclaration = functionDeclaration; @@ -140,7 +140,11 @@ public final class FunctionTranslator extends AbstractTranslator { public JsExpression translateAsLiteral() { assert getExpectedThisDescriptor(descriptor) == null; generateFunctionObject(); - return mayBeWrapInClosureCaptureExpression(mayBeWrapWithThisAlias()); + ClosureContext closureContext = ClosureUtils.captureClosure(context(), (JetElement) functionDeclaration); + if (closureContext.getDescriptors().isEmpty()) { + return mayBeWrapWithThisAlias(); + } + return wrapInClosureCaptureExpression(functionObject, closureContext); } @NotNull @@ -160,23 +164,18 @@ public final class FunctionTranslator extends AbstractTranslator { return containingClass != null; } - @NotNull - private JsExpression mayBeWrapInClosureCaptureExpression(@NotNull JsExpression wrappedExpression) { - ClosureContext closureContext = ClosureUtils.captureClosure(context(), (JetElement)functionDeclaration); - if (closureContext.getDescriptors().isEmpty()) { - return wrappedExpression; - } - return wrapInClosureCaptureExpression(wrappedExpression, closureContext); - } - @NotNull private JsExpression wrapInClosureCaptureExpression(@NotNull JsExpression wrappedExpression, - @NotNull ClosureContext closureContext) { + @NotNull ClosureContext closureContext) { JsFunction dummyFunction = new JsFunction(context().jsScope()); JsInvocation dummyFunctionInvocation = AstUtil.newInvocation(dummyFunction); for (VariableDescriptor variableDescriptor : closureContext.getDescriptors()) { dummyFunction.getParameters().add(new JsParameter(context().getNameForDescriptor(variableDescriptor))); dummyFunctionInvocation.getArguments().add(ReferenceTranslator.translateAsLocalNameReference(variableDescriptor, context())); + if (aliasForContainingClassThis != null) { + dummyFunction.getParameters().add(new JsParameter(aliasForContainingClassThis.name())); + dummyFunctionInvocation.getArguments().add(aliasForContainingClassThis.initExpression()); + } } dummyFunction.setBody(AstUtil.newBlock(new JsReturn(wrappedExpression))); return dummyFunctionInvocation; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/CaptureClosureVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/CaptureClosureVisitor.java index 021417724f8..0efd171d933 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/CaptureClosureVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/CaptureClosureVisitor.java @@ -56,6 +56,7 @@ public class CaptureClosureVisitor extends JetTreeVisitor { if (!(descriptor instanceof VariableDescriptor)) { return null; } + VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; PsiElement variableDeclaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor); if (variableDeclaration == null) { @@ -69,6 +70,8 @@ public class CaptureClosureVisitor extends JetTreeVisitor { context.put(variableDescriptor); return null; } + + boolean isLoopParameter = variableDeclaration.getNode().getElementType().equals(JetNodeTypes.LOOP_PARAMETER); if (isLoopParameter) { context.put(variableDescriptor); diff --git a/js/js.translator/testFiles/closure/cases/closureReferencingMember.kt b/js/js.translator/testFiles/closure/cases/closureReferencingMember.kt new file mode 100644 index 00000000000..8cdbf5ea0d4 --- /dev/null +++ b/js/js.translator/testFiles/closure/cases/closureReferencingMember.kt @@ -0,0 +1,24 @@ +package foo + +class A() { + + var i = 0 + + fun f() { + for (j in 0..2) { + foo { + i += j + } + } + } +} + +fun foo(f : ()->Unit) { + f() +} + +fun box() : Boolean { + val a = A() + a.f() + return a.i == 3 +} \ No newline at end of file