JS backend: fixed variable capturing in extension functions.
Fixed ClosureTest.testWrappedVariableInExtensionFun IteratorsTest.foldReducesTheFirstNElements and IteratorsTest.takeExtractsTheFirstNElements. All tests passed. (cherry picked from commit f8f1895)
This commit is contained in:
@@ -47,4 +47,8 @@ public final class ClosureTest extends SingleFileTranslationTest {
|
|||||||
public void testClosureInNestedFunctionsInMethod() throws Exception {
|
public void testClosureInNestedFunctionsInMethod() throws Exception {
|
||||||
checkFooBoxIsOk();
|
checkFooBoxIsOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWrappedVariableInExtensionFun() throws Exception {
|
||||||
|
fooBoxTest();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,19 @@ package org.jetbrains.k2js.translate.context;
|
|||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||||
|
import gnu.trove.THashMap;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class AliasingContext {
|
public class AliasingContext {
|
||||||
private static final AliasingContext ROOT = new AliasingContext(null) {
|
private static final AliasingContext ROOT = new AliasingContext(null) {
|
||||||
@Override
|
@Override
|
||||||
public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
protected JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor, boolean fromChild) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +38,11 @@ public class AliasingContext {
|
|||||||
public JsName getAliasForExpression(@NotNull JetExpression element) {
|
public JsName getAliasForExpression(@NotNull JetExpression element) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAlias(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression alias) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static AliasingContext getCleanContext() {
|
public static AliasingContext getCleanContext() {
|
||||||
@@ -53,7 +58,7 @@ public class AliasingContext {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final AliasingContext parent;
|
private final AliasingContext parent;
|
||||||
|
|
||||||
private AliasingContext(@Nullable AliasingContext parent) {
|
/*package*/ AliasingContext(@Nullable AliasingContext parent) {
|
||||||
this(parent, null, null);
|
this(parent, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +77,20 @@ public class AliasingContext {
|
|||||||
return new AliasingContext(this, Collections.singletonMap(descriptor, alias), null);
|
return new AliasingContext(this, Collections.singletonMap(descriptor, alias), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public AliasingContext notShareableThisAliased(@NotNull final DeclarationDescriptor thisDescriptor, @NotNull final JsExpression alias) {
|
||||||
|
return new AliasingContext(this) {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor, boolean fromChild) {
|
||||||
|
if (!fromChild && thisDescriptor == descriptor) {
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
return super.getAliasForDescriptor(descriptor, fromChild);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public AliasingContext withExpressionsAliased(@NotNull Map<JetExpression, JsName> aliasesForExpressions) {
|
public AliasingContext withExpressionsAliased(@NotNull Map<JetExpression, JsName> aliasesForExpressions) {
|
||||||
return new AliasingContext(this, null, aliasesForExpressions);
|
return new AliasingContext(this, null, aliasesForExpressions);
|
||||||
@@ -82,22 +101,17 @@ public class AliasingContext {
|
|||||||
return new AliasingContext(this, aliases, null);
|
return new AliasingContext(this, aliases, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||||
if (aliasesForDescriptors == null) {
|
// these aliases cannot be shared and applicable only in current context
|
||||||
return null;
|
return getAliasForDescriptor(descriptor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsExpression alias = aliasesForDescriptors.get(descriptor.getOriginal());
|
@Nullable
|
||||||
if (alias != null) {
|
protected JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor, boolean fromChild) {
|
||||||
return alias;
|
JsExpression alias = aliasesForDescriptors == null ? null : aliasesForDescriptors.get(descriptor.getOriginal());
|
||||||
}
|
return alias != null || parent == null ? alias : parent.getAliasForDescriptor(descriptor, true);
|
||||||
|
|
||||||
if (parent == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent.getAliasForDescriptor(descriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -106,6 +120,13 @@ public class AliasingContext {
|
|||||||
return alias != null || parent == null ? alias : parent.getAliasForExpression(element);
|
return alias != null || parent == null ? alias : parent.getAliasForExpression(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usages:
|
||||||
|
* 1) Local variable captured in closure. If captured in closure, any modification in closure should affect captured variable.
|
||||||
|
* So, "var count = n" wrapped as "var count = {v: n}". descriptor wil be property descriptor, alias will be JsObjectLiteral
|
||||||
|
*
|
||||||
|
* 2) Local named function.
|
||||||
|
*/
|
||||||
public void registerAlias(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression alias) {
|
public void registerAlias(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression alias) {
|
||||||
if (aliasesForDescriptors == null) {
|
if (aliasesForDescriptors == null) {
|
||||||
aliasesForDescriptors = Collections.singletonMap(descriptor, alias);
|
aliasesForDescriptors = Collections.singletonMap(descriptor, alias);
|
||||||
@@ -113,7 +134,7 @@ public class AliasingContext {
|
|||||||
else {
|
else {
|
||||||
if (aliasesForDescriptors.size() == 1) {
|
if (aliasesForDescriptors.size() == 1) {
|
||||||
Map<DeclarationDescriptor, JsExpression> singletonMap = aliasesForDescriptors;
|
Map<DeclarationDescriptor, JsExpression> singletonMap = aliasesForDescriptors;
|
||||||
aliasesForDescriptors = new HashMap<DeclarationDescriptor, JsExpression>();
|
aliasesForDescriptors = new THashMap<DeclarationDescriptor, JsExpression>();
|
||||||
aliasesForDescriptors.put(singletonMap.keySet().iterator().next(), singletonMap.values().iterator().next());
|
aliasesForDescriptors.put(singletonMap.keySet().iterator().next(), singletonMap.values().iterator().next());
|
||||||
}
|
}
|
||||||
JsExpression prev = aliasesForDescriptors.put(descriptor, alias);
|
JsExpression prev = aliasesForDescriptors.put(descriptor, alias);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public final class Namer {
|
|||||||
public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase();
|
public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase();
|
||||||
|
|
||||||
public static final String CALLEE_NAME = "$fun";
|
public static final String CALLEE_NAME = "$fun";
|
||||||
|
public static final String OUTER_CLASS_NAME = "$outer";
|
||||||
|
|
||||||
private static final String INITIALIZE_METHOD_NAME = "initialize";
|
private static final String INITIALIZE_METHOD_NAME = "initialize";
|
||||||
private static final String CLASS_OBJECT_NAME = "createClass";
|
private static final String CLASS_OBJECT_NAME = "createClass";
|
||||||
@@ -42,7 +43,7 @@ public final class Namer {
|
|||||||
private static final String BACKING_FIELD_PREFIX = "$";
|
private static final String BACKING_FIELD_PREFIX = "$";
|
||||||
private static final String SUPER_METHOD_NAME = "super_init";
|
private static final String SUPER_METHOD_NAME = "super_init";
|
||||||
private static final String ROOT_NAMESPACE = "_";
|
private static final String ROOT_NAMESPACE = "_";
|
||||||
private static final String RECEIVER_PARAMETER_NAME = "receiver";
|
private static final String RECEIVER_PARAMETER_NAME = "$receiver";
|
||||||
private static final String CLASSES_OBJECT_NAME = "classes";
|
private static final String CLASSES_OBJECT_NAME = "classes";
|
||||||
private static final String THROW_NPE_FUN_NAME = "throwNPE";
|
private static final String THROW_NPE_FUN_NAME = "throwNPE";
|
||||||
|
|
||||||
|
|||||||
@@ -61,10 +61,12 @@ public class TranslationContext {
|
|||||||
return staticContext.isEcma5();
|
return staticContext.isEcma5();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslationContext(@NotNull StaticContext staticContext,
|
private TranslationContext(
|
||||||
|
@NotNull StaticContext staticContext,
|
||||||
@NotNull DynamicContext dynamicContext,
|
@NotNull DynamicContext dynamicContext,
|
||||||
@NotNull AliasingContext aliasingContext,
|
@NotNull AliasingContext aliasingContext,
|
||||||
@Nullable UsageTracker usageTracker) {
|
@Nullable UsageTracker usageTracker
|
||||||
|
) {
|
||||||
this.dynamicContext = dynamicContext;
|
this.dynamicContext = dynamicContext;
|
||||||
this.staticContext = staticContext;
|
this.staticContext = staticContext;
|
||||||
this.aliasingContext = aliasingContext;
|
this.aliasingContext = aliasingContext;
|
||||||
@@ -72,10 +74,17 @@ public class TranslationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslationContext(@NotNull TranslationContext parent, @NotNull AliasingContext aliasingContext) {
|
private TranslationContext(@NotNull TranslationContext parent, @NotNull AliasingContext aliasingContext) {
|
||||||
dynamicContext = parent.dynamicContext;
|
this(parent.staticContext, parent.dynamicContext, aliasingContext, parent.usageTracker);
|
||||||
staticContext = parent.staticContext;
|
}
|
||||||
this.aliasingContext = aliasingContext;
|
|
||||||
usageTracker = parent.usageTracker;
|
private TranslationContext(
|
||||||
|
@NotNull TranslationContext parent,
|
||||||
|
@NotNull JsFunction fun,
|
||||||
|
@NotNull AliasingContext aliasingContext,
|
||||||
|
@Nullable UsageTracker usageTracker
|
||||||
|
) {
|
||||||
|
this(parent.staticContext, DynamicContext.newContext(fun.getScope(), fun.getBody()), aliasingContext,
|
||||||
|
usageTracker == null ? parent.usageTracker : usageTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UsageTracker usageTracker() {
|
public UsageTracker usageTracker() {
|
||||||
@@ -88,7 +97,7 @@ public class TranslationContext {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public TranslationContext contextWithScope(@NotNull JsFunction fun) {
|
public TranslationContext contextWithScope(@NotNull JsFunction fun) {
|
||||||
return contextWithScope(fun, aliasingContext, usageTracker);
|
return new TranslationContext(this, fun, aliasingContext, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -100,8 +109,13 @@ public class TranslationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public TranslationContext contextWithScope(@NotNull JsFunction fun, @NotNull AliasingContext aliasingContext, @Nullable UsageTracker usageTracker) {
|
public TranslationContext newFunctionBody(
|
||||||
return contextWithScope(fun.getScope(), fun.getBody(), aliasingContext, usageTracker);
|
@NotNull JsFunction fun,
|
||||||
|
@Nullable AliasingContext aliasingContext,
|
||||||
|
@Nullable UsageTracker usageTracker
|
||||||
|
) {
|
||||||
|
return new TranslationContext(this, fun, aliasingContext == null ? new AliasingContext(this.aliasingContext) : aliasingContext,
|
||||||
|
usageTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -115,8 +129,8 @@ public class TranslationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public TranslationContext innerContextWithThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsName alias) {
|
public TranslationContext innerContextWithThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsNameRef alias) {
|
||||||
return new TranslationContext(this, aliasingContext.inner(correspondingDescriptor, alias.makeRef()));
|
return new TranslationContext(this, aliasingContext.inner(correspondingDescriptor, alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+1
-2
@@ -57,8 +57,7 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitNamedFunction(@NotNull JetNamedFunction expression,
|
public Void visitNamedFunction(@NotNull JetNamedFunction expression, @NotNull TranslationContext context) {
|
||||||
@NotNull TranslationContext context) {
|
|
||||||
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
||||||
if (descriptor.getModality() == Modality.ABSTRACT) {
|
if (descriptor.getModality() == Modality.ABSTRACT) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator;
|
|||||||
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
|
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
|
||||||
import org.jetbrains.k2js.translate.reference.*;
|
import org.jetbrains.k2js.translate.reference.*;
|
||||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||||
|
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
|
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
|
||||||
@@ -149,15 +149,13 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
@NotNull
|
@NotNull
|
||||||
// assume it is a local variable declaration
|
// assume it is a local variable declaration
|
||||||
public JsNode visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) {
|
public JsNode visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) {
|
||||||
VariableDescriptor descriptor = context.bindingContext().get(BindingContext.VARIABLE, expression);
|
VariableDescriptor descriptor = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.VARIABLE, expression);
|
||||||
assert descriptor != null;
|
|
||||||
JsExpression initializer = translateInitializerForProperty(expression, context);
|
JsExpression initializer = translateInitializerForProperty(expression, context);
|
||||||
JsName name = context.getNameForDescriptor(descriptor);
|
JsName name = context.getNameForDescriptor(descriptor);
|
||||||
if (descriptor.isVar() && context.bindingContext().get(BindingContext.CAPTURED_IN_CLOSURE, descriptor) != null) {
|
if (descriptor.isVar() && context.bindingContext().get(BindingContext.CAPTURED_IN_CLOSURE, descriptor) != null) {
|
||||||
// well, wrap it
|
// well, wrap it
|
||||||
JsNameRef alias = new JsNameRef("v", new JsNameRef(name));
|
JsNameRef alias = new JsNameRef("v", new JsNameRef(name));
|
||||||
initializer = new JsObjectLiteral(
|
initializer = JsAstUtils.wrapValue(alias, initializer == null ? JsLiteral.NULL : initializer);
|
||||||
Collections.singletonList(new JsPropertyInitializer(alias, initializer == null ? JsLiteral.NULL : initializer)));
|
|
||||||
context.aliasingContext().registerAlias(descriptor, alias);
|
context.aliasingContext().registerAlias(descriptor, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -21,6 +21,7 @@ import com.google.dart.compiler.backend.js.ast.JsFunction;
|
|||||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsParameter;
|
import com.google.dart.compiler.backend.js.ast.JsParameter;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
|
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
|
||||||
|
import com.intellij.util.SmartList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
@@ -29,14 +30,15 @@ import org.jetbrains.jet.lang.descriptors.Modality;
|
|||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||||
|
import org.jetbrains.k2js.translate.context.AliasingContext;
|
||||||
import org.jetbrains.k2js.translate.context.Namer;
|
import org.jetbrains.k2js.translate.context.Namer;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
||||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
|
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
|
||||||
@@ -76,24 +78,18 @@ public final class FunctionTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private TranslationContext getFunctionBodyContext() {
|
private TranslationContext getFunctionBodyContext() {
|
||||||
|
AliasingContext aliasingContext;
|
||||||
if (isExtensionFunction()) {
|
if (isExtensionFunction()) {
|
||||||
return getFunctionBodyContextForExtensionFunction();
|
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||||
|
assert expectedReceiverDescriptor != null;
|
||||||
|
extensionFunctionReceiverName = functionObject.getScope().declareName(Namer.getReceiverParameterName());
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
aliasingContext = context().aliasingContext().inner(expectedReceiverDescriptor, extensionFunctionReceiverName.makeRef());
|
||||||
}
|
}
|
||||||
return getContextWithFunctionBodyBlock();
|
else {
|
||||||
}
|
aliasingContext = null;
|
||||||
|
}
|
||||||
@NotNull
|
return context().newFunctionBody(functionObject, aliasingContext, null);
|
||||||
private TranslationContext getFunctionBodyContextForExtensionFunction() {
|
|
||||||
TranslationContext contextWithFunctionBodyBlock = getContextWithFunctionBodyBlock();
|
|
||||||
extensionFunctionReceiverName = contextWithFunctionBodyBlock.scope().declareName(Namer.getReceiverParameterName());
|
|
||||||
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
|
||||||
assert expectedReceiverDescriptor != null;
|
|
||||||
return contextWithFunctionBodyBlock.innerContextWithThisAliased(expectedReceiverDescriptor, extensionFunctionReceiverName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private TranslationContext getContextWithFunctionBodyBlock() {
|
|
||||||
return context().contextWithScope(functionObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -125,7 +121,11 @@ public final class FunctionTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<JsParameter> translateParameters() {
|
private List<JsParameter> translateParameters() {
|
||||||
List<JsParameter> jsParameters = new ArrayList<JsParameter>();
|
if (extensionFunctionReceiverName == null && descriptor.getValueParameters().isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<JsParameter> jsParameters = new SmartList<JsParameter>();
|
||||||
mayBeAddThisParameterForExtensionFunction(jsParameters);
|
mayBeAddThisParameterForExtensionFunction(jsParameters);
|
||||||
addParameters(jsParameters, descriptor, context());
|
addParameters(jsParameters, descriptor, context());
|
||||||
return jsParameters;
|
return jsParameters;
|
||||||
@@ -145,6 +145,6 @@ public final class FunctionTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isExtensionFunction() {
|
private boolean isExtensionFunction() {
|
||||||
return JsDescriptorUtils.isExtension(descriptor) && !(functionDeclaration instanceof JetFunctionLiteral);
|
return JsDescriptorUtils.isExtension(descriptor) && !(functionDeclaration instanceof JetFunctionLiteralExpression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-8
@@ -76,15 +76,16 @@ public class LiteralFunctionTranslator {
|
|||||||
TranslationContext funContext;
|
TranslationContext funContext;
|
||||||
boolean asInner;
|
boolean asInner;
|
||||||
ClassDescriptor outerClass;
|
ClassDescriptor outerClass;
|
||||||
AliasingContext aliasingContext = rootContext.aliasingContext();
|
AliasingContext aliasingContext;
|
||||||
DeclarationDescriptor receiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
DeclarationDescriptor receiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||||
JsName receiverName;
|
JsName receiverName;
|
||||||
if (receiverDescriptor == null) {
|
if (receiverDescriptor == null) {
|
||||||
receiverName = null;
|
receiverName = null;
|
||||||
|
aliasingContext = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
receiverName = fun.getScope().declareName(Namer.getReceiverParameterName());
|
receiverName = fun.getScope().declareName(Namer.getReceiverParameterName());
|
||||||
aliasingContext = aliasingContext.inner(receiverDescriptor, receiverName.makeRef());
|
aliasingContext = outerContext.aliasingContext().inner(receiverDescriptor, receiverName.makeRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
||||||
@@ -95,7 +96,7 @@ public class LiteralFunctionTranslator {
|
|||||||
assert outerClass != null;
|
assert outerClass != null;
|
||||||
|
|
||||||
if (receiverDescriptor == null) {
|
if (receiverDescriptor == null) {
|
||||||
aliasingContext = aliasingContext.inner(outerClass, new JsNameRef("o", fun.getName().makeRef()));
|
aliasingContext = outerContext.aliasingContext().notShareableThisAliased(outerClass, new JsNameRef("o", fun.getName().makeRef()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -103,8 +104,8 @@ public class LiteralFunctionTranslator {
|
|||||||
asInner = DescriptorUtils.isTopLevelDeclaration(descriptor);
|
asInner = DescriptorUtils.isTopLevelDeclaration(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
funContext = rootContext.contextWithScope(fun, aliasingContext,
|
funContext = outerContext.newFunctionBody(fun, aliasingContext,
|
||||||
new UsageTracker(descriptor, outerContext.usageTracker(), outerClass));
|
new UsageTracker(descriptor, outerContext.usageTracker(), outerClass));
|
||||||
|
|
||||||
fun.getBody().getStatements().addAll(translateFunctionBody(descriptor, declaration, funContext).getStatements());
|
fun.getBody().getStatements().addAll(translateFunctionBody(descriptor, declaration, funContext).getStatements());
|
||||||
|
|
||||||
@@ -160,10 +161,10 @@ public class LiteralFunctionTranslator {
|
|||||||
@NotNull ClassDescriptor descriptor,
|
@NotNull ClassDescriptor descriptor,
|
||||||
@NotNull ClassTranslator classTranslator) {
|
@NotNull ClassTranslator classTranslator) {
|
||||||
JsFunction fun = createFunction();
|
JsFunction fun = createFunction();
|
||||||
JsNameRef outerClassRef = fun.getScope().declareName("$this").makeRef();
|
JsNameRef outerClassRef = fun.getScope().declareName(Namer.OUTER_CLASS_NAME).makeRef();
|
||||||
UsageTracker usageTracker = new UsageTracker(descriptor, null, outerClass);
|
UsageTracker usageTracker = new UsageTracker(descriptor, null, outerClass);
|
||||||
TranslationContext funContext = rootContext.contextWithScope(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef),
|
TranslationContext funContext = rootContext.newFunctionBody(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef),
|
||||||
usageTracker);
|
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();
|
||||||
|
|||||||
+2
-3
@@ -129,11 +129,10 @@ public final class InlinedCallExpressionTranslator extends AbstractCallExpressio
|
|||||||
@NotNull
|
@NotNull
|
||||||
private TranslationContext contextWithAlias(@NotNull TranslationContext contextWithAliasForThisExpression,
|
private TranslationContext contextWithAlias(@NotNull TranslationContext contextWithAliasForThisExpression,
|
||||||
@NotNull JsExpression aliasExpression, @Nullable DeclarationDescriptor descriptorToAlias) {
|
@NotNull JsExpression aliasExpression, @Nullable DeclarationDescriptor descriptorToAlias) {
|
||||||
TranslationContext newContext = contextWithAliasForThisExpression;
|
|
||||||
TemporaryVariable aliasForReceiver = context().declareTemporary(aliasExpression);
|
TemporaryVariable aliasForReceiver = context().declareTemporary(aliasExpression);
|
||||||
assert descriptorToAlias != null;
|
assert descriptorToAlias != null;
|
||||||
newContext =
|
TranslationContext newContext =
|
||||||
newContext.innerContextWithThisAliased(descriptorToAlias, aliasForReceiver.name());
|
contextWithAliasForThisExpression.innerContextWithThisAliased(descriptorToAlias, aliasForReceiver.reference());
|
||||||
newContext.addStatementToCurrentBlock(aliasForReceiver.assignmentExpression().makeStmt());
|
newContext.addStatementToCurrentBlock(aliasForReceiver.assignmentExpression().makeStmt());
|
||||||
return newContext;
|
return newContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -281,4 +281,9 @@ public final class JsAstUtils {
|
|||||||
to.add(new JsInvocation(EMPTY_REF, new JsInvocation(packageBlockFunction)).makeStmt());
|
to.add(new JsInvocation(EMPTY_REF, new JsInvocation(packageBlockFunction)).makeStmt());
|
||||||
return packageBlockFunction;
|
return packageBlockFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JsObjectLiteral wrapValue(@NotNull JsExpression label, @NotNull JsExpression value) {
|
||||||
|
return new JsObjectLiteral(Collections.singletonList(new JsPropertyInitializer(label, value)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun Any.foo(n: Int): ()->Boolean {
|
||||||
|
var count = n
|
||||||
|
return { --count >= 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): Boolean {
|
||||||
|
return 1.foo(3)() && !1.foo(0)()
|
||||||
|
}
|
||||||
@@ -16,14 +16,12 @@ class IteratorsTest {
|
|||||||
assertEquals(arrayList(144, 233, 377, 610, 987), fibonacci().filter { it > 100 }.takeWhile { it < 1000 }.toList())
|
assertEquals(arrayList(144, 233, 377, 610, 987), fibonacci().filter { it > 100 }.takeWhile { it < 1000 }.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO fix and enable this test
|
test fun foldReducesTheFirstNElements() {
|
||||||
fun foldReducesTheFirstNElements() {
|
|
||||||
val sum = { (a: Int, b: Int) -> a + b }
|
val sum = { (a: Int, b: Int) -> a + b }
|
||||||
assertEquals(arrayList(13, 21, 34, 55, 89).fold(0, sum), fibonacci().filter { it > 10 }.take(5).fold(0, sum))
|
assertEquals(arrayList(13, 21, 34, 55, 89).fold(0, sum), fibonacci().filter { it > 10 }.take(5).fold(0, sum))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO fix and enable this test
|
test fun takeExtractsTheFirstNElements() {
|
||||||
fun takeExtractsTheFirstNElements() {
|
|
||||||
assertEquals(arrayList(0, 1, 1, 2, 3, 5, 8, 13, 21, 34), fibonacci().take(10).toList())
|
assertEquals(arrayList(0, 1, 1, 2, 3, 5, 8, 13, 21, 34), fibonacci().take(10).toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user