For-of calls [Symbol.iterator]() on RHS to get iterator
authorwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Jun 2014 17:31:54 +0000 (17:31 +0000)
committerwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Jun 2014 17:31:54 +0000 (17:31 +0000)
R=rossberg@chromium.org
BUG=http://code.google.com/p/v8/issues/detail?id=2735
LOG=N

Review URL: https://codereview.chromium.org/332663004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21820 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

17 files changed:
include/v8.h
src/arm/full-codegen-arm.cc
src/arm64/full-codegen-arm64.cc
src/array-iterator.js
src/ast.h
src/bootstrapper.cc
src/contexts.h
src/flag-definitions.h
src/generator.js
src/heap.h
src/ia32/full-codegen-ia32.cc
src/mips/full-codegen-mips.cc
src/parser.cc
src/x64/full-codegen-x64.cc
src/x87/full-codegen-x87.cc
test/mjsunit/harmony/iteration-semantics.js
tools/generate-runtime-tests.py

index e037ca7..56492f7 100644 (file)
@@ -5543,7 +5543,7 @@ class Internals {
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 162;
+  static const int kEmptyStringRootIndex = 163;
 
   // The external allocation limit should be below 256 MB on all architectures
   // to avoid that resource-constrained embedders run low on memory.
index bb4618a..241991c 100644 (file)
@@ -1273,8 +1273,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
 
-  // var iterator = iterable[@@iterator]()
-  VisitForAccumulatorValue(stmt->assign_iterator());
+  // var iterable = subject
+  VisitForAccumulatorValue(stmt->assign_iterable());
 
   // As with for-in, skip the loop if the iterator is null or undefined.
   __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
@@ -1282,16 +1282,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   __ CompareRoot(r0, Heap::kNullValueRootIndex);
   __ b(eq, loop_statement.break_label());
 
-  // Convert the iterator to a JS object.
-  Label convert, done_convert;
-  __ JumpIfSmi(r0, &convert);
-  __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
-  __ b(ge, &done_convert);
-  __ bind(&convert);
-  __ push(r0);
-  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
-  __ bind(&done_convert);
-  __ push(r0);
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
 
   // Loop entry.
   __ bind(loop_statement.continue_label());
index ba3b5d0..b74a058 100644 (file)
@@ -1280,8 +1280,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
 
-  // var iterator = iterable[@@iterator]()
-  VisitForAccumulatorValue(stmt->assign_iterator());
+  // var iterable = subject
+  VisitForAccumulatorValue(stmt->assign_iterable());
 
   // As with for-in, skip the loop if the iterator is null or undefined.
   Register iterator = x0;
@@ -1290,16 +1290,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   __ JumpIfRoot(iterator, Heap::kNullValueRootIndex,
                 loop_statement.break_label());
 
-  // Convert the iterator to a JS object.
-  Label convert, done_convert;
-  __ JumpIfSmi(iterator, &convert);
-  __ CompareObjectType(iterator, x1, x1, FIRST_SPEC_OBJECT_TYPE);
-  __ B(ge, &done_convert);
-  __ Bind(&convert);
-  __ Push(iterator);
-  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
-  __ Bind(&done_convert);
-  __ Push(iterator);
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
 
   // Loop entry.
   __ Bind(loop_statement.continue_label());
index a96b9cb..9511b6d 100644 (file)
@@ -18,6 +18,11 @@ var arrayIterationKindSymbol = GLOBAL_PRIVATE("ArrayIterator#kind");
 function ArrayIterator() {}
 
 
+// TODO(wingo): Update section numbers when ES6 has stabilized.  The
+// section numbers below are already out of date as of the May 2014
+// draft.
+
+
 // 15.4.5.1 CreateArrayIterator Abstract Operation
 function CreateArrayIterator(array, kind) {
   var object = ToObject(array);
@@ -35,6 +40,12 @@ function CreateIteratorResultObject(value, done) {
 }
 
 
+// 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]
+function ArrayIteratorIterator() {
+    return this;
+}
+
+
 // 15.4.5.2.2 ArrayIterator.prototype.next( )
 function ArrayIteratorNext() {
   var iterator = ToObject(this);
@@ -98,6 +109,9 @@ function SetUpArrayIterator() {
   InstallFunctions(ArrayIterator.prototype, DONT_ENUM, $Array(
     'next', ArrayIteratorNext
   ));
+  %FunctionSetName(ArrayIteratorIterator, '[Symbol.iterator]');
+  %SetProperty(ArrayIterator.prototype, symbolIterator, ArrayIteratorIterator,
+      DONT_ENUM | DONT_DELETE | READ_ONLY);
 }
 SetUpArrayIterator();
 
index 0882b25..f79c2d2 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -956,11 +956,13 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
   void Initialize(Expression* each,
                   Expression* subject,
                   Statement* body,
+                  Expression* assign_iterable,
                   Expression* assign_iterator,
                   Expression* next_result,
                   Expression* result_done,
                   Expression* assign_each) {
     ForEachStatement::Initialize(each, subject, body);
+    assign_iterable_ = assign_iterable;
     assign_iterator_ = assign_iterator;
     next_result_ = next_result;
     result_done_ = result_done;
@@ -971,7 +973,12 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
     return subject();
   }
 
-  // var iterator = iterable;
+  // var iterable = subject;
+  Expression* assign_iterable() const {
+    return assign_iterable_;
+  }
+
+  // var iterator = iterable[Symbol.iterator]();
   Expression* assign_iterator() const {
     return assign_iterator_;
   }
@@ -1006,6 +1013,7 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
         back_edge_id_(GetNextId(zone)) {
   }
 
+  Expression* assign_iterable_;
   Expression* assign_iterator_;
   Expression* next_result_;
   Expression* result_done_;
index 19a4394..87e1d20 100644 (file)
@@ -1622,6 +1622,10 @@ void Genesis::InstallExperimentalNativeFunctions() {
     INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
     INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
   }
+
+  if (FLAG_harmony_symbols) {
+    INSTALL_NATIVE(Symbol, "symbolIterator", iterator_symbol);
+  }
 }
 
 #undef INSTALL_NATIVE
index 51a7162..2792c2e 100644 (file)
@@ -187,7 +187,8 @@ enum BindingFlags {
     generator_object_prototype_map) \
   V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map) \
   V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
-  V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map)
+  V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \
+  V(ITERATOR_SYMBOL_INDEX, Symbol, iterator_symbol)
 
 // JSFunctions are pairs (context, function code), sometimes also called
 // closures. A Context object is used to represent function contexts and
@@ -360,6 +361,7 @@ class Context: public FixedArray {
     ITERATOR_RESULT_MAP_INDEX,
     MAP_ITERATOR_MAP_INDEX,
     SET_ITERATOR_MAP_INDEX,
+    ITERATOR_SYMBOL_INDEX,
 
     // Properties from here are treated as weak references by the full GC.
     // Scavenge treats them as strong references.
index 558b91c..f36a577 100644 (file)
@@ -180,6 +180,7 @@ DEFINE_implication(harmony, harmony_arrays)
 DEFINE_implication(harmony_modules, harmony_scoping)
 DEFINE_implication(harmony_collections, harmony_symbols)
 DEFINE_implication(harmony_generators, harmony_symbols)
+DEFINE_implication(harmony_iteration, harmony_symbols)
 
 DEFINE_implication(harmony, es_staging)
 DEFINE_implication(es_staging, harmony_maths)
index abcb867..a0c2aff 100644 (file)
@@ -62,6 +62,7 @@ function SetUpGenerators() {
                    DONT_ENUM | DONT_DELETE | READ_ONLY,
                    ["next", GeneratorObjectNext,
                     "throw", GeneratorObjectThrow]);
+  %FunctionSetName(GeneratorObjectIterator, '[Symbol.iterator]');
   %SetProperty(GeneratorObjectPrototype, symbolIterator, GeneratorObjectIterator,
       DONT_ENUM | DONT_DELETE | READ_ONLY);
   %SetProperty(GeneratorObjectPrototype, "constructor",
index b9da734..c50107f 100644 (file)
@@ -277,6 +277,7 @@ namespace internal {
   V(constructor_string, "constructor")                                   \
   V(dot_result_string, ".result")                                        \
   V(dot_for_string, ".for.")                                             \
+  V(dot_iterable_string, ".iterable")                                    \
   V(dot_iterator_string, ".iterator")                                    \
   V(dot_generator_object_string, ".generator_object")                    \
   V(eval_string, "eval")                                                 \
index 030e6f6..c9e280d 100644 (file)
@@ -1214,8 +1214,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
 
-  // var iterator = iterable[@@iterator]()
-  VisitForAccumulatorValue(stmt->assign_iterator());
+  // var iterable = subject
+  VisitForAccumulatorValue(stmt->assign_iterable());
 
   // As with for-in, skip the loop if the iterator is null or undefined.
   __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
@@ -1223,15 +1223,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   __ CompareRoot(eax, Heap::kNullValueRootIndex);
   __ j(equal, loop_statement.break_label());
 
-  // Convert the iterator to a JS object.
-  Label convert, done_convert;
-  __ JumpIfSmi(eax, &convert);
-  __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
-  __ j(above_equal, &done_convert);
-  __ bind(&convert);
-  __ push(eax);
-  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
-  __ bind(&done_convert);
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
 
   // Loop entry.
   __ bind(loop_statement.continue_label());
index da4756a..9b613b4 100644 (file)
@@ -1282,8 +1282,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
 
-  // var iterator = iterable[@@iterator]()
-  VisitForAccumulatorValue(stmt->assign_iterator());
+  // var iterable = subject
+  VisitForAccumulatorValue(stmt->assign_iterable());
   __ mov(a0, v0);
 
   // As with for-in, skip the loop if the iterator is null or undefined.
@@ -1292,17 +1292,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   __ LoadRoot(at, Heap::kNullValueRootIndex);
   __ Branch(loop_statement.break_label(), eq, a0, Operand(at));
 
-  // Convert the iterator to a JS object.
-  Label convert, done_convert;
-  __ JumpIfSmi(a0, &convert);
-  __ GetObjectType(a0, a1, a1);
-  __ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
-  __ bind(&convert);
-  __ push(a0);
-  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
-  __ mov(a0, v0);
-  __ bind(&done_convert);
-  __ push(a0);
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
 
   // Loop entry.
   __ bind(loop_statement.continue_label());
index 5106556..9bca3d5 100644 (file)
@@ -2778,21 +2778,46 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
 
   if (for_of != NULL) {
     Factory* heap_factory = isolate()->factory();
+    Variable* iterable = scope_->DeclarationScope()->NewTemporary(
+        heap_factory->dot_iterable_string());
     Variable* iterator = scope_->DeclarationScope()->NewTemporary(
         heap_factory->dot_iterator_string());
     Variable* result = scope_->DeclarationScope()->NewTemporary(
         heap_factory->dot_result_string());
 
+    Expression* assign_iterable;
     Expression* assign_iterator;
     Expression* next_result;
     Expression* result_done;
     Expression* assign_each;
 
-    // var iterator = iterable;
+    // var iterable = subject;
     {
+      Expression* iterable_proxy = factory()->NewVariableProxy(iterable);
+      assign_iterable = factory()->NewAssignment(
+          Token::ASSIGN, iterable_proxy, subject, subject->position());
+    }
+
+    // var iterator = iterable[Symbol.iterator]();
+    {
+      Expression* iterable_proxy = factory()->NewVariableProxy(iterable);
+      Handle<Symbol> iterator_symbol(
+          isolate()->native_context()->iterator_symbol(), isolate());
+      Expression* iterator_symbol_literal = factory()->NewLiteral(
+          iterator_symbol, RelocInfo::kNoPosition);
+      // FIXME(wingo): Unhappily, it will be a common error that the RHS of a
+      // for-of doesn't have a Symbol.iterator property.  We should do better
+      // than informing the user that "undefined is not a function".
+      int pos = subject->position();
+      Expression* iterator_property = factory()->NewProperty(
+          iterable_proxy, iterator_symbol_literal, pos);
+      ZoneList<Expression*>* iterator_arguments =
+          new(zone()) ZoneList<Expression*>(0, zone());
+      Expression* iterator_call = factory()->NewCall(
+          iterator_property, iterator_arguments, pos);
       Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
       assign_iterator = factory()->NewAssignment(
-          Token::ASSIGN, iterator_proxy, subject, RelocInfo::kNoPosition);
+          Token::ASSIGN, iterator_proxy, iterator_call, RelocInfo::kNoPosition);
     }
 
     // var result = iterator.next();
@@ -2832,7 +2857,11 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
     }
 
     for_of->Initialize(each, subject, body,
-                       assign_iterator, next_result, result_done, assign_each);
+                       assign_iterable,
+                       assign_iterator,
+                       next_result,
+                       result_done,
+                       assign_each);
   } else {
     stmt->Initialize(each, subject, body);
   }
index 8de4226..1816abe 100644 (file)
@@ -1252,24 +1252,17 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
 
-  // var iterator = iterable[@@iterator]()
-  VisitForAccumulatorValue(stmt->assign_iterator());
+  // var iterable = subject
+  VisitForAccumulatorValue(stmt->assign_iterable());
 
-  // As with for-in, skip the loop if the iterator is null or undefined.
+  // As with for-in, skip the loop if the iterable is null or undefined.
   __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
   __ j(equal, loop_statement.break_label());
   __ CompareRoot(rax, Heap::kNullValueRootIndex);
   __ j(equal, loop_statement.break_label());
 
-  // Convert the iterator to a JS object.
-  Label convert, done_convert;
-  __ JumpIfSmi(rax, &convert);
-  __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
-  __ j(above_equal, &done_convert);
-  __ bind(&convert);
-  __ Push(rax);
-  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
-  __ bind(&done_convert);
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
 
   // Loop entry.
   __ bind(loop_statement.continue_label());
index d5a9886..05daab6 100644 (file)
@@ -1211,8 +1211,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
 
-  // var iterator = iterable[@@iterator]()
-  VisitForAccumulatorValue(stmt->assign_iterator());
+  // var iterable = subject
+  VisitForAccumulatorValue(stmt->assign_iterable());
 
   // As with for-in, skip the loop if the iterator is null or undefined.
   __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
@@ -1220,15 +1220,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   __ CompareRoot(eax, Heap::kNullValueRootIndex);
   __ j(equal, loop_statement.break_label());
 
-  // Convert the iterator to a JS object.
-  Label convert, done_convert;
-  __ JumpIfSmi(eax, &convert);
-  __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
-  __ j(above_equal, &done_convert);
-  __ bind(&convert);
-  __ push(eax);
-  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
-  __ bind(&done_convert);
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
 
   // Loop entry.
   __ bind(loop_statement.continue_label());
index 2449115..27033e1 100644 (file)
@@ -27,6 +27,7 @@
 
 // Flags: --harmony-iteration
 // Flags: --harmony-generators --harmony-scoping --harmony-proxies
+// Flags: --harmony-symbols
 
 // Test for-of semantics.
 
@@ -41,13 +42,19 @@ function* values() {
   }
 }
 
+function wrap_iterator(iterator) {
+    var iterable = {};
+    iterable[Symbol.iterator] = function() { return iterator; };
+    return iterable;
+}
+
 function integers_until(max) {
   function next() {
     var ret = { value: this.n, done: this.n == max };
     this.n++;
     return ret;
   }
-  return { next: next, n: 0 }
+  return wrap_iterator({ next: next, n: 0 });
 }
 
 function results(results) {
@@ -55,7 +62,7 @@ function results(results) {
   function next() {
     return results[i++];
   }
-  return { next: next }
+  return wrap_iterator({ next: next });
 }
 
 function* integers_from(n) {
@@ -72,44 +79,44 @@ function sum(x, tail) {
   return x + tail;
 }
 
-function fold(cons, seed, iter) {
-  for (var x of iter) {
+function fold(cons, seed, iterable) {
+  for (var x of iterable) {
     seed = cons(x, seed);
   }
   return seed;
 }
 
-function* take(iter, n) {
+function* take(iterable, n) {
   if (n == 0) return;
-  for (let x of iter) {
+  for (let x of iterable) {
     yield x;
     if (--n == 0) break;
   }
 }
 
-function nth(iter, n) {
-  for (let x of iter) {
+function nth(iterable, n) {
+  for (let x of iterable) {
     if (n-- == 0) return x;
   }
   throw "unreachable";
 }
 
-function* skip_every(iter, n) {
+function* skip_every(iterable, n) {
   var i = 0;
-  for (let x of iter) {
+  for (let x of iterable) {
     if (++i % n == 0) continue;
     yield x;
   }
 }
 
-function* iter_map(iter, f) {
-  for (var x of iter) {
+function* iter_map(iterable, f) {
+  for (var x of iterable) {
     yield f(x);
   }
 }
-function nested_fold(cons, seed, iter) {
+function nested_fold(cons, seed, iterable) {
   var visited = []
-  for (let x of iter) {
+  for (let x of iterable) {
     for (let y of x) {
       seed = cons(y, seed);
     }
@@ -117,8 +124,8 @@ function nested_fold(cons, seed, iter) {
   return seed;
 }
 
-function* unreachable(iter) {
-  for (let x of iter) {
+function* unreachable(iterable) {
+  for (let x of iterable) {
     throw "not reached";
   }
 }
@@ -141,17 +148,19 @@ function never_getter(o, prop) {
   return o;
 }
 
-function remove_next_after(iter, n) {
+function remove_next_after(iterable, n) {
+  var iterator = iterable[Symbol.iterator]();
   function next() {
     if (n-- == 0) delete this.next;
-    return iter.next();
+    return iterator.next();
   }
-  return { next: next }
+  return wrap_iterator({ next: next });
 }
 
-function poison_next_after(iter, n) {
+function poison_next_after(iterable, n) {
+  var iterator = iterable[Symbol.iterator]();
   function next() {
-    return iter.next();
+    return iterator.next();
   }
   function next_getter() {
     if (n-- < 0)
@@ -160,7 +169,7 @@ function poison_next_after(iter, n) {
   }
   var o = {};
   Object.defineProperty(o, 'next', { get: next_getter });
-  return o;
+  return wrap_iterator(o);
 }
 
 // Now, the tests.
@@ -223,33 +232,33 @@ assertEquals(45,
 assertEquals(45,
              fold(sum, 0, poison_next_after(integers_until(10), 10)));
 
-function labelled_continue(iter) {
+function labelled_continue(iterable) {
   var n = 0;
 outer:
   while (true) {
     n++;
-    for (var x of iter) continue outer;
+    for (var x of iterable) continue outer;
     break;
   }
   return n;
 }
 assertEquals(11, labelled_continue(integers_until(10)));
 
-function labelled_break(iter) {
+function labelled_break(iterable) {
   var n = 0;
 outer:
   while (true) {
     n++;
-    for (var x of iter) break outer;
+    for (var x of iterable) break outer;
   }
   return n;
 }
 assertEquals(1, labelled_break(integers_until(10)));
 
 // Test continue/break in catch.
-function catch_control(iter, k) {
+function catch_control(iterable, k) {
   var n = 0;
-  for (var x of iter) {
+  for (var x of iterable) {
     try {
       return k(x);
     } catch (e) {
@@ -274,9 +283,9 @@ assertEquals(5,
                            }));
 
 // Test continue/break in try.
-function try_control(iter, k) {
+function try_control(iterable, k) {
   var n = 0;
-  for (var x of iter) {
+  for (var x of iterable) {
     try {
       var e = k(x);
       if (e == "continue") continue;
@@ -313,16 +322,17 @@ assertEquals([1, 2],
                           .map(transparent_proxy))));
 
 // Proxy iterators.
-function poison_proxy_after(x, n) {
-  return Proxy.create({
+function poison_proxy_after(iterable, n) {
+  var iterator = iterable[Symbol.iterator]();
+  return wrap_iterator(Proxy.create({
     get: function(receiver, name) {
       if (name == 'next' && n-- < 0) throw "unreachable";
-      return x[name];
+      return iterator[name];
     },
     // Needed for integers_until(10)'s this.n++.
     set: function(receiver, name, val) {
-      return x[name] = val;
+      return iterator[name] = val;
     }
-  });
+  }));
 }
 assertEquals(45, fold(sum, 0, poison_proxy_after(integers_until(10), 10)));
index 1811f9e..a4414be 100755 (executable)
@@ -51,7 +51,7 @@ EXPECTED_FUNCTION_COUNT = 358
 EXPECTED_FUZZABLE_COUNT = 325
 EXPECTED_CCTEST_COUNT = 6
 EXPECTED_UNKNOWN_COUNT = 5
-EXPECTED_BUILTINS_COUNT = 797
+EXPECTED_BUILTINS_COUNT = 798
 
 
 # Don't call these at all.