Bug 1216966 - Part 4: Update a big comment about for-loops in Parser.cpp. r=efaust.
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 14 Oct 2015 08:58:11 -0500
changeset 305292 cd16e0e4852bbced3db97c67b849653dab26d123
parent 305291 1d4b1adfb5724a94ae6c82c7c211b607ee1e9a4a
child 305293 bb5b95d5f621a62758a4d26f06ee15d98f2ac43f
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1216966
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1216966 - Part 4: Update a big comment about for-loops in Parser.cpp. r=efaust.
js/src/frontend/Parser.cpp
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5268,53 +5268,54 @@ Parser<FullParseHandler>::forStatement(Y
                 return null();
             modifier = TokenStream::None;
         }
     }
 
     MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
     MOZ_ASSERT(!!blockObj == (isForDecl && (pn1->isOp(JSOP_DEFLET) || pn1->isOp(JSOP_DEFCONST))));
 
-    // All forms of for-loop (for(;;), for-in, for-of) generate an implicit
-    // block to store any lexical variables declared by the loop-head.  We
-    // implement this by desugaring such loops.  These:
+    // If the head of a for-loop declares any lexical variables, we generate an
+    // implicit block to store them. We implement this by desugaring. These:
+    //
+    //     for (let/const <bindings>; <test>; <update>) <stmt>
+    //     for (let <pattern> in <expr>) <stmt>
+    //     for (let <pattern> of <expr>) <stmt>
     //
-    //   for (let/const <pattern-and-assigns>; <test>; <update>) <stmt>
-    //   for (let <pattern> in <expr>) <stmt>
-    //   for (let <pattern> of <expr>) <stmt>
+    // transform into roughly the same parse trees as these (using deprecated
+    // let-block syntax):
     //
-    // transform into almost these desugarings:
-    //
-    //   let (<pattern-and-assigns>) { for (; <test>; <update>) <stmt> }
-    //   let (<pattern>) { for (<pattern> in <expr>) <stmt> }
-    //   let (<pattern>) { for (<pattern> of <expr>) <stmt> }
+    //     let (<bindings>) { for (; <test>; <update>) <stmt> }
+    //     let (<pattern>) { for (<pattern> in <expr>) <stmt> }
+    //     let (<pattern>) { for (<pattern> of <expr>) <stmt> }
     //
-    // This desugaring is not *quite* correct.  Assignments in the head of a
-    // let-block are evaluated *outside* the scope of the variables declared by
-    // the let-block-head.  But ES6 mandates that they be evaluated in the same
-    // scope, triggering used-before-initialization temporal dead zone errors
-    // as necessary.  Bug 1069480 will fix this.
+    // This desugaring is not ES6 compliant. Initializers in the head of a
+    // let-block are evaluated *outside* the scope of the variables being
+    // initialized. ES6 mandates that they be evaluated in the same scope,
+    // triggering used-before-initialization temporal dead zone errors as
+    // necessary. See bug 1216623 on scoping and bug 1069480 on TDZ.
     //
-    // Additionally, ES6 mandates that *each iteration* of a for-loop create a
-    // fresh binding of loop variables.  For example:
+    // Additionally, in ES6, each iteration of a for-loop creates a fresh
+    // binding of the loop variables. For example:
     //
-    //   var funcs = [];
-    //   for (let i = 0; i < 2; i++)
-    //     funcs.push(function() { return i; });
-    //   assertEq(funcs[0](), 0);
-    //   assertEq(funcs[1](), 1);
+    //     var funcs = [];
+    //     for (let i = 0; i < 2; i++)
+    //         funcs.push(function() { return i; });
+    //     assertEq(funcs[0](), 0);  // the two closures capture...
+    //     assertEq(funcs[1](), 1);  // ...two different `i` bindings
     //
     // These semantics are implemented by "freshening" the implicit block --
     // changing the scope chain to a fresh clone of the instantaneous block
     // object -- each iteration, just before evaluating the "update" in
-    // for(;;) loops.  (We don't implement this freshening for for-in/of loops,
-    // but soon: bug 449811.)  No freshening occurs in for (const ...;;) as
-    // there's no point (you can't reassign consts), and moreover the spec
-    // requires it (which fact isn't exposed in-language but can be observed
-    // through the Debugger API).
+    // for(;;) loops. We don't implement this freshening for for-in/of loops
+    // yet: bug 449811.
+    //
+    // No freshening occurs in `for (const ...;;)` as there's no point: you
+    // can't reassign consts. This is observable through the Debugger API. (The
+    // ES6 spec also skips cloning the environment in this case.)
     //
     // If the for-loop head includes a lexical declaration, then we create an
     // implicit block scope, and:
     //
     //   * forLetImpliedBlock is the node for the implicit block scope.
     //   * forLetDecl is the node for the decl 'let/const <pattern>'.
     //
     // Otherwise both are null.