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 8ff3c743a73..d42809704d5 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 @@ -35,4 +35,8 @@ public final class ClosureTest extends SingleFileTranslationTest { public void testClosureReferencingMember() throws Exception { fooBoxTest(); } + + public void testLocalParameterInLocalNamedFunction() throws Exception { + fooBoxTest(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java index 165a83806c2..d1c0cd03f92 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java @@ -21,7 +21,6 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.Named; import org.jetbrains.jet.lang.psi.JetExpression; @@ -237,7 +236,7 @@ public class TranslationContext { } public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { - if (usageTracker != null && descriptor instanceof ClassDescriptor) { + if (usageTracker != null) { usageTracker.triggerUsed(descriptor); } return aliasingContext.getAliasForDescriptor(descriptor); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.java index 6b3e9439b6e..b049f979dd3 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.java @@ -16,23 +16,189 @@ package org.jetbrains.k2js.translate.context; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import com.intellij.util.Consumer; +import com.intellij.util.SmartList; +import com.intellij.util.containers.OrderedSet; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; + +import java.util.List; +import java.util.Set; + +public final class UsageTracker { + @Nullable + private final ClassDescriptor trackedClassDescriptor; + @NotNull + private final MemberDescriptor memberDescriptor; + + @Nullable + private final UsageTracker parent; + @Nullable + private List children; -public class UsageTracker { - private final DeclarationDescriptor trackedDescriptor; private boolean used; + @Nullable + private Set capturedVariables; + private ClassDescriptor outerClassDescriptor; - public UsageTracker(DeclarationDescriptor trackedDescriptor) { - this.trackedDescriptor = trackedDescriptor; + public UsageTracker(@NotNull MemberDescriptor memberDescriptor, @Nullable UsageTracker parent, @Nullable ClassDescriptor trackedClassDescriptor) { + this.memberDescriptor = memberDescriptor; + this.trackedClassDescriptor = trackedClassDescriptor; + this.parent = parent; + if (parent != null) { + parent.addChild(this); + } } public boolean isUsed() { return used; } + private void addChild(UsageTracker child) { + if (children == null) { + children = new SmartList(); + } + children.add(child); + } + + private void addCapturedMember(CallableDescriptor descriptor) { + if (capturedVariables == null) { + capturedVariables = new OrderedSet(); + } + capturedVariables.add(descriptor); + } + public void triggerUsed(DeclarationDescriptor descriptor) { - if (trackedDescriptor == descriptor) { - used = true; + if ((descriptor instanceof PropertyDescriptor || descriptor instanceof PropertyAccessorDescriptor)) { + checkOuterClass(descriptor); + } + else if (descriptor instanceof VariableDescriptor) { + VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; + if ((capturedVariables == null || !capturedVariables.contains(variableDescriptor)) && + !isAncestor(memberDescriptor, variableDescriptor)) { + addCapturedMember(variableDescriptor); + } + } + else if (descriptor instanceof SimpleFunctionDescriptor) { + checkOuterClass(descriptor); + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + // local named function + CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor; + if (!JsDescriptorUtils.isExtension(callableDescriptor) && + !(containingDeclaration instanceof ClassOrNamespaceDescriptor) && + !isAncestor(memberDescriptor, descriptor)) { + addCapturedMember(callableDescriptor); + } + } + else if (descriptor instanceof ClassDescriptor) { + if (trackedClassDescriptor == descriptor) { + used = true; + } + else if (parent != null) { + UsageTracker p = parent; + do { + if (p.trackedClassDescriptor == descriptor) { + break; + } + } + while ((p = p.parent) != null); + } } } + + private void checkOuterClass(DeclarationDescriptor descriptor) { + if (outerClassDescriptor == null) { + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + if (containingDeclaration instanceof ClassDescriptor) { + outerClassDescriptor = (ClassDescriptor) containingDeclaration; + } + } + } + + @Nullable + public ClassDescriptor getOuterClassDescriptor() { + if (outerClassDescriptor == null && parent != null) { + UsageTracker p = parent; + do { + if (p.outerClassDescriptor != null) { + return p.outerClassDescriptor; + } + } + while ((p = p.parent) != null); + } + return outerClassDescriptor; + } + + public void forEachCaptured(Consumer consumer) { + forEachCaptured(consumer, this, children == null ? null : new THashSet()); + } + + private boolean isOneOfTheMyParentsIsAncestor(VariableDescriptor parameterDescriptor, UsageTracker requestor) { + if (requestor == this) { + return false; + } + + FunctionDescriptor paramOwner = (FunctionDescriptor) parameterDescriptor.getContainingDeclaration(); + UsageTracker p = parent; + do { + if (p.memberDescriptor == paramOwner) { + return true; + } + } + while ((p = p.parent) != null && p != requestor); + return false; + } + + private void forEachCaptured(Consumer consumer, UsageTracker requestor, @Nullable THashSet visited) { + if (capturedVariables != null) { + for (CallableDescriptor variable : capturedVariables) { + if (variable instanceof VariableDescriptor && isOneOfTheMyParentsIsAncestor((VariableDescriptor) variable, requestor)) { + continue; + } + + if (visited == null || visited.add(variable)) { + consumer.consume(variable); + } + } + } + if (children != null) { + for (UsageTracker child : children) { + child.forEachCaptured(consumer, requestor, visited); + } + } + } + + public boolean hasCaptured() { + if (capturedVariables != null) { + assert !capturedVariables.isEmpty(); + return true; + } + + if (children != null) { + for (UsageTracker child : children) { + if (child.hasCaptured()) { + return true; + } + } + } + return false; + } + + // differs from DescriptorUtils - fails if reach NamespaceDescriptor + private static boolean isAncestor( + @NotNull DeclarationDescriptor ancestor, + @NotNull DeclarationDescriptor declarationDescriptor + ) { + DeclarationDescriptor descriptor = declarationDescriptor.getContainingDeclaration(); + while (descriptor != null && !(descriptor instanceof NamespaceDescriptor)) { + if (ancestor == descriptor) { + return true; + } + descriptor = descriptor.getContainingDeclaration(); + } + return false; + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerDeclarationTranslator.java index 6c90a0c0545..ec70e00d437 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerDeclarationTranslator.java @@ -17,70 +17,56 @@ package org.jetbrains.k2js.translate.expression; import com.google.dart.compiler.backend.js.ast.*; +import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; -import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.utils.closure.ClosureContext; -import org.jetbrains.k2js.translate.utils.closure.ClosureUtils; -import java.util.Collections; import java.util.List; abstract class InnerDeclarationTranslator { - protected final ClosureContext closureContext; protected final TranslationContext context; protected final JsFunction fun; - public InnerDeclarationTranslator(@NotNull JetElement element, - @NotNull DeclarationDescriptor descriptor, + public InnerDeclarationTranslator( @NotNull TranslationContext context, - @NotNull JsFunction fun) { + @NotNull JsFunction fun + ) { this.context = context; - closureContext = ClosureUtils.captureClosure(context.bindingContext(), element, descriptor); this.fun = fun; } - protected List getValueParameters() { - return Collections.emptyList(); - } - public JsExpression translate(@NotNull JsNameRef nameRef, @Nullable JsExpression self) { - if (closureContext.getDescriptors().isEmpty() && self == JsLiteral.NULL) { + boolean hasCaptured = context.usageTracker().hasCaptured(); + if (!hasCaptured && self == JsLiteral.NULL) { return createExpression(nameRef, self); } - else { - JsInvocation invocation = createInvocation(nameRef, self); - addCapturedValueParameters(invocation); - return invocation; + + JsInvocation invocation = createInvocation(nameRef, self); + if (hasCaptured) { + final List expressions = invocation.getArguments(); + context.usageTracker().forEachCaptured(new Consumer() { + @Override + public void consume(CallableDescriptor descriptor) { + JsName name; + if (descriptor instanceof VariableDescriptor) { + name = context.getNameForDescriptor(descriptor); + } + else { + name = ((JsNameRef) context.getAliasForDescriptor(descriptor)).getName(); + assert name != null; + } + fun.getParameters().add(new JsParameter(name)); + expressions.add(name.makeRef()); + } + }); } + return invocation; } protected abstract JsExpression createExpression(@NotNull JsNameRef nameRef, @Nullable JsExpression self); protected abstract JsInvocation createInvocation(@NotNull JsNameRef nameRef, @Nullable JsExpression self); - - private void addCapturedValueParameters(JsInvocation bind) { - if (closureContext.getDescriptors().isEmpty()) { - return; - } - - List expressions = bind.getArguments(); - for (CallableDescriptor descriptor : closureContext.getDescriptors()) { - JsName name; - if (descriptor instanceof VariableDescriptor) { - name = context.getNameForDescriptor(descriptor); - } - else { - name = ((JsNameRef) context.getAliasForDescriptor(descriptor)).getName(); - assert name != null; - } - fun.getParameters().add(new JsParameter(name)); - expressions.add(name.makeRef()); - } - } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerFunctionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerFunctionTranslator.java index 8aeee15761d..d6892bb2231 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerFunctionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerFunctionTranslator.java @@ -22,28 +22,20 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.k2js.translate.context.TranslationContext; -import java.util.List; - class InnerFunctionTranslator extends InnerDeclarationTranslator { private final FunctionDescriptor descriptor; - public InnerFunctionTranslator(@NotNull JetElement element, + public InnerFunctionTranslator( @NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context, - @NotNull JsFunction fun) { - super(element, descriptor, context, fun); + @NotNull JsFunction fun + ) { + super(context, fun); this.descriptor = descriptor; } - @Override - protected List getValueParameters() { - return descriptor.getValueParameters(); - } - @SuppressWarnings("MethodOverloadsMethodOfSuperclass") @NotNull public JsExpression translate(@NotNull JsNameRef nameRef, @NotNull TranslationContext outerContext) { @@ -62,7 +54,8 @@ class InnerFunctionTranslator extends InnerDeclarationTranslator { @NotNull private JsExpression getThis(TranslationContext outerContext) { - ClassDescriptor outerClassDescriptor = closureContext.outerClassDescriptor; + //noinspection ConstantConditions + ClassDescriptor outerClassDescriptor = context.usageTracker().getOuterClassDescriptor(); if (outerClassDescriptor != null && descriptor.getReceiverParameter() == null) { return outerContext.getThisObject(outerClassDescriptor); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerObjectTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerObjectTranslator.java index b53f8e20d0c..f6a66769cb9 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerObjectTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/InnerObjectTranslator.java @@ -19,13 +19,14 @@ package org.jetbrains.k2js.translate.expression; import com.google.dart.compiler.backend.js.ast.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.k2js.translate.context.TranslationContext; class InnerObjectTranslator extends InnerDeclarationTranslator { - public InnerObjectTranslator(@NotNull JetElement element, @NotNull ClassDescriptor descriptor, @NotNull TranslationContext context, @NotNull JsFunction fun) { - super(element, descriptor, context, fun); + public InnerObjectTranslator( + @NotNull TranslationContext context, + @NotNull JsFunction fun + ) { + super(context, fun); } @Override diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java index 81d9d199c38..150a6e36f3d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java @@ -97,21 +97,20 @@ public class LiteralFunctionTranslator { if (receiverDescriptor == null) { aliasingContext = aliasingContext.inner(outerClass, new JsNameRef("o", fun.getName().makeRef())); } - - funContext = rootContext.contextWithScope(fun, aliasingContext, new UsageTracker(outerClass)); } else { outerClass = null; asInner = DescriptorUtils.isTopLevelDeclaration(descriptor); - - funContext = rootContext.contextWithScope(fun, aliasingContext, outerContext.usageTracker()); } + funContext = rootContext.contextWithScope(fun, aliasingContext, + new UsageTracker(descriptor, outerContext.usageTracker(), outerClass)); + fun.getBody().getStatements().addAll(translateFunctionBody(descriptor, declaration, funContext).getStatements()); InnerFunctionTranslator translator = null; if (!asInner) { - translator = new InnerFunctionTranslator(declaration.asElement(), descriptor, funContext, fun); + translator = new InnerFunctionTranslator(descriptor, funContext, fun); } if (asInner) { @@ -161,12 +160,13 @@ public class LiteralFunctionTranslator { JsFunction fun = createFunction(); JsNameRef outerClassRef = fun.getScope().declareName("$this").makeRef(); TranslationContext funContext = rootContext - .contextWithScope(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef), new UsageTracker(outerClass)); + .contextWithScope(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef), new UsageTracker(descriptor, null, + outerClass)); fun.getBody().getStatements().add(new JsReturn(classTranslator.translate(funContext))); JetClassBody body = declaration.getBody(); assert body != null; - InnerObjectTranslator translator = new InnerObjectTranslator(body, descriptor, funContext, fun); + InnerObjectTranslator translator = new InnerObjectTranslator(funContext, fun); return translator.translate(createReference(fun), funContext.usageTracker().isUsed() ? outerClassRef : null); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java index 2517a4224fd..bde452cca57 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java @@ -51,15 +51,15 @@ public final class ReferenceTranslator { } @NotNull - public static JsExpression translateAsLocalNameReference(@NotNull DeclarationDescriptor referencedDescriptor, + public static JsExpression translateAsLocalNameReference(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) { - if (referencedDescriptor instanceof FunctionDescriptor || referencedDescriptor instanceof VariableDescriptor) { - JsExpression alias = context.aliasingContext().getAliasForDescriptor(referencedDescriptor); + if (descriptor instanceof FunctionDescriptor || descriptor instanceof VariableDescriptor) { + JsExpression alias = context.getAliasForDescriptor(descriptor); if (alias != null) { return alias; } } - return context.getNameForDescriptor(referencedDescriptor).makeRef(); + return context.getNameForDescriptor(descriptor).makeRef(); } @NotNull 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 deleted file mode 100644 index 97828f0bb98..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/CaptureClosureVisitor.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.k2js.translate.utils.closure; - -import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.JetNodeTypes; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; -import org.jetbrains.k2js.translate.utils.BindingUtils; -import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; - -class CaptureClosureVisitor extends JetTreeVisitor { - @NotNull - private final BindingContext bindingContext; - @NotNull - private final DeclarationDescriptor functionDescriptor; - - /*package*/ CaptureClosureVisitor(@NotNull DeclarationDescriptor descriptor, @NotNull BindingContext bindingContext) { - this.bindingContext = bindingContext; - functionDescriptor = descriptor; - } - - @Override - public Void visitJetElement(JetElement element, ClosureContext data) { - if (element instanceof JetValueArgument) { - JetExpression expression = ((JetValueArgument) element).getArgumentExpression(); - if (expression != null) { - expression.accept(this, data); - } - } - else if (!(element instanceof JetNamedFunction)) { - return super.visitJetElement(element, data); - } - - return null; - } - - @Override - public Void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, - @NotNull ClosureContext context) { - if (expression.getNode().getElementType() == JetNodeTypes.OPERATION_REFERENCE) { - return null; - } - - DeclarationDescriptor descriptor = BindingUtils.getNullableDescriptorForReferenceExpression(bindingContext, expression); - if (!(descriptor instanceof VariableDescriptor)) { - if (descriptor instanceof SimpleFunctionDescriptor) { - checkSimpleFunction(context, (SimpleFunctionDescriptor) descriptor); - } - return null; - } - - VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; - if (captured(variableDescriptor, context)) { - context.put(variableDescriptor); - } - - return null; - } - - private void checkSimpleFunction(ClosureContext context, @Nullable SimpleFunctionDescriptor descriptor) { - if (descriptor == null || descriptor.getName().isSpecial()) { - return; - } - - checkOuterClassDescriptor(descriptor, context); - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - // local named function - if (!JsDescriptorUtils.isExtension(descriptor) && !(containingDeclaration instanceof ClassOrNamespaceDescriptor) && !isAncestor(functionDescriptor, descriptor)) { - context.put(descriptor); - } - } - - private boolean captured(VariableDescriptor descriptor, ClosureContext context) { - if (descriptor instanceof PropertyDescriptor) { - checkOuterClassDescriptor(descriptor, context); - return false; - } - - // is not working, try test life - init is captured, but this method returns false - //if (bindingContext.get(BindingContext.CAPTURED_IN_CLOSURE, descriptor) != Boolean.TRUE) { - // return false; - //} - - if (isAncestor(functionDescriptor, descriptor)) { - return false; - } - - if (descriptor instanceof LocalVariableDescriptor || descriptor instanceof ValueParameterDescriptor) { - return true; - } - - PsiElement variableDeclaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor); - if (variableDeclaration == null) { - // "it" doesn't have declaration - return false; - } - - return (!descriptor.isVar() && variableDeclaration instanceof JetProperty) || - variableDeclaration.getNode().getElementType().equals(JetNodeTypes.LOOP_PARAMETER); - } - - // differs from DescriptorUtils - fails if reach NamespaceDescriptor - public static boolean isAncestor(@NotNull DeclarationDescriptor ancestor, - @NotNull DeclarationDescriptor declarationDescriptor) { - DeclarationDescriptor descriptor = declarationDescriptor.getContainingDeclaration(); - while (descriptor != null && !(descriptor instanceof NamespaceDescriptor)) { - if (ancestor == descriptor) { - return true; - } - descriptor = descriptor.getContainingDeclaration(); - } - return false; - } - - - private static void checkOuterClassDescriptor(DeclarationDescriptor descriptor, ClosureContext context) { - if (context.outerClassDescriptor == null) { - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - if (containingDeclaration instanceof ClassDescriptor) { - context.outerClassDescriptor = (ClassDescriptor) containingDeclaration; - } - } - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/ClosureContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/ClosureContext.java deleted file mode 100644 index 0501968c9a6..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/ClosureContext.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.k2js.translate.utils.closure; - -import com.intellij.util.containers.OrderedSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; - -import java.util.Collection; -import java.util.Set; - -public final class ClosureContext { - @NotNull - private final Set descriptors = new OrderedSet(); - - @Nullable - public ClassDescriptor outerClassDescriptor; - - /*package*/ void put(@NotNull CallableDescriptor descriptor) { - descriptors.add(descriptor); - } - - @NotNull - public Collection getDescriptors() { - return descriptors; - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/ClosureUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/ClosureUtils.java deleted file mode 100644 index aff6c2af0f3..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/closure/ClosureUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.k2js.translate.utils.closure; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.resolve.BindingContext; - -public final class ClosureUtils { - private ClosureUtils() { - } - - @NotNull - public static ClosureContext captureClosure(@NotNull BindingContext bindingContext, @NotNull JetElement element, @NotNull DeclarationDescriptor descriptor) { - CaptureClosureVisitor captureClosureVisitor = new CaptureClosureVisitor(descriptor, bindingContext); - ClosureContext closureContext = new ClosureContext(); - element.acceptChildren(captureClosureVisitor, closureContext); - return closureContext; - } -} diff --git a/js/js.translator/testFiles/closure/cases/localParameterInLocalNamedFunction.kt b/js/js.translator/testFiles/closure/cases/localParameterInLocalNamedFunction.kt new file mode 100644 index 00000000000..1fbd4546d46 --- /dev/null +++ b/js/js.translator/testFiles/closure/cases/localParameterInLocalNamedFunction.kt @@ -0,0 +1,27 @@ +package foo + +fun getLastFocused(callback:(window:Any?)->Unit) { + callback(null) +} + +fun box(): Boolean { + var result = "no" + createTab(true) { + result = it + } + return result == "yes" +} + +fun createTab(focusWindow:Boolean, callback:((String)->Unit)?) { + getLastFocused { + fun createTab() { + if (focusWindow && callback != null) { + callback("yes") + } + } + + if (it == null) { + createTab() + } + } +}