From e786e62fd72f8e851939cc9e682d2d3151ffe21a Mon Sep 17 00:00:00 2001 From: develar Date: Thu, 8 Aug 2013 21:28:41 +0400 Subject: [PATCH] JS backend: fixed variable capturing in extension functions. Fixed ClosureTest.testWrappedVariableInExtensionFun IteratorsTest.foldReducesTheFirstNElements and IteratorsTest.takeExtractsTheFirstNElements. All tests passed. (cherry picked from commit f8f1895) --- .../k2js/test/semantics/ClosureTest.java | 4 ++ .../translate/context/AliasingContext.java | 55 +++++++++++++------ .../k2js/translate/context/Namer.java | 3 +- .../translate/context/TranslationContext.java | 36 ++++++++---- .../declaration/DeclarationBodyVisitor.java | 3 +- .../expression/ExpressionVisitor.java | 8 +-- .../expression/FunctionTranslator.java | 40 +++++++------- .../expression/LiteralFunctionTranslator.java | 17 +++--- .../InlinedCallExpressionTranslator.java | 5 +- .../k2js/translate/utils/JsAstUtils.java | 5 ++ .../cases/wrappedVariableInExtensionFun.kt | 10 ++++ .../stdlib/test/iterators/IteratorsTest.kt | 6 +- 12 files changed, 121 insertions(+), 71 deletions(-) create mode 100644 js/js.translator/testFiles/closure/cases/wrappedVariableInExtensionFun.kt 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 73c53fa77e6..cd655efc88d 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 @@ -47,4 +47,8 @@ public final class ClosureTest extends SingleFileTranslationTest { public void testClosureInNestedFunctionsInMethod() throws Exception { checkFooBoxIsOk(); } + + public void testWrappedVariableInExtensionFun() throws Exception { + fooBoxTest(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java index e3d396a0734..6b149f716f3 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java @@ -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.JsName; +import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import java.util.Collections; -import java.util.HashMap; import java.util.Map; public class AliasingContext { private static final AliasingContext ROOT = new AliasingContext(null) { @Override - public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { + protected JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor, boolean fromChild) { return null; } @@ -38,6 +38,11 @@ public class AliasingContext { public JsName getAliasForExpression(@NotNull JetExpression element) { return null; } + + @Override + public void registerAlias(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression alias) { + throw new IllegalStateException(); + } }; public static AliasingContext getCleanContext() { @@ -53,7 +58,7 @@ public class AliasingContext { @Nullable private final AliasingContext parent; - private AliasingContext(@Nullable AliasingContext parent) { + /*package*/ AliasingContext(@Nullable AliasingContext parent) { this(parent, null, null); } @@ -72,6 +77,20 @@ public class AliasingContext { 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 public AliasingContext withExpressionsAliased(@NotNull Map aliasesForExpressions) { return new AliasingContext(this, null, aliasesForExpressions); @@ -82,22 +101,17 @@ public class AliasingContext { return new AliasingContext(this, aliases, null); } + @Nullable public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { - if (aliasesForDescriptors == null) { - return null; - } + // these aliases cannot be shared and applicable only in current context + return getAliasForDescriptor(descriptor, false); + } - JsExpression alias = aliasesForDescriptors.get(descriptor.getOriginal()); - if (alias != null) { - return alias; - } - - if (parent == null) { - return null; - } - - return parent.getAliasForDescriptor(descriptor); + @Nullable + protected JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor, boolean fromChild) { + JsExpression alias = aliasesForDescriptors == null ? null : aliasesForDescriptors.get(descriptor.getOriginal()); + return alias != null || parent == null ? alias : parent.getAliasForDescriptor(descriptor, true); } @Nullable @@ -106,6 +120,13 @@ public class AliasingContext { 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) { if (aliasesForDescriptors == null) { aliasesForDescriptors = Collections.singletonMap(descriptor, alias); @@ -113,7 +134,7 @@ public class AliasingContext { else { if (aliasesForDescriptors.size() == 1) { Map singletonMap = aliasesForDescriptors; - aliasesForDescriptors = new HashMap(); + aliasesForDescriptors = new THashMap(); aliasesForDescriptors.put(singletonMap.keySet().iterator().next(), singletonMap.values().iterator().next()); } JsExpression prev = aliasesForDescriptors.put(descriptor, alias); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java index 7fe9001c75b..2c05bf0422d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java @@ -32,6 +32,7 @@ public final class Namer { public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase(); 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 CLASS_OBJECT_NAME = "createClass"; @@ -42,7 +43,7 @@ public final class Namer { private static final String BACKING_FIELD_PREFIX = "$"; private static final String SUPER_METHOD_NAME = "super_init"; 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 THROW_NPE_FUN_NAME = "throwNPE"; 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 10d74fc9cb7..5b18a31f162 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 @@ -61,10 +61,12 @@ public class TranslationContext { return staticContext.isEcma5(); } - private TranslationContext(@NotNull StaticContext staticContext, + private TranslationContext( + @NotNull StaticContext staticContext, @NotNull DynamicContext dynamicContext, @NotNull AliasingContext aliasingContext, - @Nullable UsageTracker usageTracker) { + @Nullable UsageTracker usageTracker + ) { this.dynamicContext = dynamicContext; this.staticContext = staticContext; this.aliasingContext = aliasingContext; @@ -72,10 +74,17 @@ public class TranslationContext { } private TranslationContext(@NotNull TranslationContext parent, @NotNull AliasingContext aliasingContext) { - dynamicContext = parent.dynamicContext; - staticContext = parent.staticContext; - this.aliasingContext = aliasingContext; - usageTracker = parent.usageTracker; + this(parent.staticContext, parent.dynamicContext, aliasingContext, 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() { @@ -88,7 +97,7 @@ public class TranslationContext { @NotNull public TranslationContext contextWithScope(@NotNull JsFunction fun) { - return contextWithScope(fun, aliasingContext, usageTracker); + return new TranslationContext(this, fun, aliasingContext, null); } @NotNull @@ -100,8 +109,13 @@ public class TranslationContext { } @NotNull - public TranslationContext contextWithScope(@NotNull JsFunction fun, @NotNull AliasingContext aliasingContext, @Nullable UsageTracker usageTracker) { - return contextWithScope(fun.getScope(), fun.getBody(), aliasingContext, usageTracker); + public TranslationContext newFunctionBody( + @NotNull JsFunction fun, + @Nullable AliasingContext aliasingContext, + @Nullable UsageTracker usageTracker + ) { + return new TranslationContext(this, fun, aliasingContext == null ? new AliasingContext(this.aliasingContext) : aliasingContext, + usageTracker); } @NotNull @@ -115,8 +129,8 @@ public class TranslationContext { } @NotNull - public TranslationContext innerContextWithThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsName alias) { - return new TranslationContext(this, aliasingContext.inner(correspondingDescriptor, alias.makeRef())); + public TranslationContext innerContextWithThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsNameRef alias) { + return new TranslationContext(this, aliasingContext.inner(correspondingDescriptor, alias)); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java index ade4008bede..24f478a0571 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java @@ -57,8 +57,7 @@ public class DeclarationBodyVisitor extends TranslatorVisitor { } @Override - public Void visitNamedFunction(@NotNull JetNamedFunction expression, - @NotNull TranslationContext context) { + public Void visitNamedFunction(@NotNull JetNamedFunction expression, @NotNull TranslationContext context) { FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression); if (descriptor.getModality() == Modality.ABSTRACT) { return null; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index a42259fa1f6..f71631d4d65 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -39,10 +39,10 @@ import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator; import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator; import org.jetbrains.k2js.translate.reference.*; 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.mutator.AssignToExpressionMutator; -import java.util.Collections; import java.util.List; import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression; @@ -149,15 +149,13 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull // assume it is a local variable declaration public JsNode visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) { - VariableDescriptor descriptor = context.bindingContext().get(BindingContext.VARIABLE, expression); - assert descriptor != null; + VariableDescriptor descriptor = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.VARIABLE, expression); JsExpression initializer = translateInitializerForProperty(expression, context); JsName name = context.getNameForDescriptor(descriptor); if (descriptor.isVar() && context.bindingContext().get(BindingContext.CAPTURED_IN_CLOSURE, descriptor) != null) { // well, wrap it JsNameRef alias = new JsNameRef("v", new JsNameRef(name)); - initializer = new JsObjectLiteral( - Collections.singletonList(new JsPropertyInitializer(alias, initializer == null ? JsLiteral.NULL : initializer))); + initializer = JsAstUtils.wrapValue(alias, initializer == null ? JsLiteral.NULL : initializer); context.aliasingContext().registerAlias(descriptor, alias); } 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 b5cf99828d3..9c2f4afa1b7 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 @@ -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.JsParameter; import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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.psi.JetDeclarationWithBody; 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.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor; @@ -76,24 +78,18 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull private TranslationContext getFunctionBodyContext() { + AliasingContext aliasingContext; 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(); - } - - @NotNull - 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); + else { + aliasingContext = null; + } + return context().newFunctionBody(functionObject, aliasingContext, null); } @NotNull @@ -125,7 +121,11 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull private List translateParameters() { - List jsParameters = new ArrayList(); + if (extensionFunctionReceiverName == null && descriptor.getValueParameters().isEmpty()) { + return Collections.emptyList(); + } + + List jsParameters = new SmartList(); mayBeAddThisParameterForExtensionFunction(jsParameters); addParameters(jsParameters, descriptor, context()); return jsParameters; @@ -145,6 +145,6 @@ public final class FunctionTranslator extends AbstractTranslator { } private boolean isExtensionFunction() { - return JsDescriptorUtils.isExtension(descriptor) && !(functionDeclaration instanceof JetFunctionLiteral); + return JsDescriptorUtils.isExtension(descriptor) && !(functionDeclaration instanceof JetFunctionLiteralExpression); } } 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 bf3387cc989..b89ae0cef48 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 @@ -76,15 +76,16 @@ public class LiteralFunctionTranslator { TranslationContext funContext; boolean asInner; ClassDescriptor outerClass; - AliasingContext aliasingContext = rootContext.aliasingContext(); + AliasingContext aliasingContext; DeclarationDescriptor receiverDescriptor = getExpectedReceiverDescriptor(descriptor); JsName receiverName; if (receiverDescriptor == null) { receiverName = null; + aliasingContext = null; } else { receiverName = fun.getScope().declareName(Namer.getReceiverParameterName()); - aliasingContext = aliasingContext.inner(receiverDescriptor, receiverName.makeRef()); + aliasingContext = outerContext.aliasingContext().inner(receiverDescriptor, receiverName.makeRef()); } if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) { @@ -95,7 +96,7 @@ public class LiteralFunctionTranslator { assert outerClass != 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 { @@ -103,8 +104,8 @@ public class LiteralFunctionTranslator { asInner = DescriptorUtils.isTopLevelDeclaration(descriptor); } - funContext = rootContext.contextWithScope(fun, aliasingContext, - new UsageTracker(descriptor, outerContext.usageTracker(), outerClass)); + funContext = outerContext.newFunctionBody(fun, aliasingContext, + new UsageTracker(descriptor, outerContext.usageTracker(), outerClass)); fun.getBody().getStatements().addAll(translateFunctionBody(descriptor, declaration, funContext).getStatements()); @@ -160,10 +161,10 @@ public class LiteralFunctionTranslator { @NotNull ClassDescriptor descriptor, @NotNull ClassTranslator classTranslator) { 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); - TranslationContext funContext = rootContext.contextWithScope(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef), - usageTracker); + TranslationContext funContext = rootContext.newFunctionBody(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef), + usageTracker); fun.getBody().getStatements().add(new JsReturn(classTranslator.translate(funContext))); JetClassBody body = declaration.getBody(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java index 6414167e32e..15450a2049e 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java @@ -129,11 +129,10 @@ public final class InlinedCallExpressionTranslator extends AbstractCallExpressio @NotNull private TranslationContext contextWithAlias(@NotNull TranslationContext contextWithAliasForThisExpression, @NotNull JsExpression aliasExpression, @Nullable DeclarationDescriptor descriptorToAlias) { - TranslationContext newContext = contextWithAliasForThisExpression; TemporaryVariable aliasForReceiver = context().declareTemporary(aliasExpression); assert descriptorToAlias != null; - newContext = - newContext.innerContextWithThisAliased(descriptorToAlias, aliasForReceiver.name()); + TranslationContext newContext = + contextWithAliasForThisExpression.innerContextWithThisAliased(descriptorToAlias, aliasForReceiver.reference()); newContext.addStatementToCurrentBlock(aliasForReceiver.assignmentExpression().makeStmt()); return newContext; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java index 44ea882b910..cf61dab9d69 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java @@ -281,4 +281,9 @@ public final class JsAstUtils { to.add(new JsInvocation(EMPTY_REF, new JsInvocation(packageBlockFunction)).makeStmt()); return packageBlockFunction; } + + @NotNull + public static JsObjectLiteral wrapValue(@NotNull JsExpression label, @NotNull JsExpression value) { + return new JsObjectLiteral(Collections.singletonList(new JsPropertyInitializer(label, value))); + } } diff --git a/js/js.translator/testFiles/closure/cases/wrappedVariableInExtensionFun.kt b/js/js.translator/testFiles/closure/cases/wrappedVariableInExtensionFun.kt new file mode 100644 index 00000000000..a784daf554d --- /dev/null +++ b/js/js.translator/testFiles/closure/cases/wrappedVariableInExtensionFun.kt @@ -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)() +} diff --git a/libraries/stdlib/test/iterators/IteratorsTest.kt b/libraries/stdlib/test/iterators/IteratorsTest.kt index 91041149a88..fae3fc23b97 100644 --- a/libraries/stdlib/test/iterators/IteratorsTest.kt +++ b/libraries/stdlib/test/iterators/IteratorsTest.kt @@ -16,14 +16,12 @@ class IteratorsTest { assertEquals(arrayList(144, 233, 377, 610, 987), fibonacci().filter { it > 100 }.takeWhile { it < 1000 }.toList()) } - // TODO fix and enable this test - fun foldReducesTheFirstNElements() { + test fun foldReducesTheFirstNElements() { 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)) } - // TODO fix and enable this test - fun takeExtractsTheFirstNElements() { + test fun takeExtractsTheFirstNElements() { assertEquals(arrayList(0, 1, 1, 2, 3, 5, 8, 13, 21, 34), fibonacci().take(10).toList()) }