Bug 728079 - "Assertion failure: pn2->pn_u.binary.iflags & 0x1" with JS 1.7, for-of loop, and destructuring. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 13 Sep 2012 07:56:52 -0500
changeset 107479 5acfcf041a4002ead1914420f19eeb4719cfc453
parent 107478 1612f075c42ddafe502c67010fadfc518fc9cbf8
child 107480 2085233469a0e140c9dd499b47bd9156a43c3e00
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersWaldo
bugs728079
milestone18.0a1
Bug 728079 - "Assertion failure: pn2->pn_u.binary.iflags & 0x1" with JS 1.7, for-of loop, and destructuring. r=Waldo.
js/src/frontend/Parser.cpp
js/src/jit-test/tests/for-of/bug-728079-js17-1.js
js/src/jit-test/tests/for-of/bug-728079-js17-2.js
js/src/jit-test/tests/for-of/bug-728079-js17-3.js
js/src/jit-test/tests/for-of/bug-728079-js17-4.js
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3088,30 +3088,32 @@ Parser::forStatement()
 
         /* Check that the left side of the 'in' or 'of' is valid. */
         if (forDecl
             ? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST)
 #if JS_HAS_DESTRUCTURING
                || (versionNumber() == JSVERSION_1_7 &&
                    pn->isOp(JSOP_ITER) &&
                    !(pn->pn_iflags & JSITER_FOREACH) &&
+                   !forOf &&
                    (pn1->pn_head->isKind(PNK_OBJECT) ||
                     (pn1->pn_head->isKind(PNK_ARRAY) &&
                      pn1->pn_head->pn_count != 2) ||
                     (pn1->pn_head->isKind(PNK_ASSIGN) &&
                      (!pn1->pn_head->pn_left->isKind(PNK_ARRAY) ||
                       pn1->pn_head->pn_left->pn_count != 2))))
 #endif
               )
             : (!pn1->isKind(PNK_NAME) &&
                !pn1->isKind(PNK_DOT) &&
 #if JS_HAS_DESTRUCTURING
                ((versionNumber() == JSVERSION_1_7 &&
                  pn->isOp(JSOP_ITER) &&
-                 !(pn->pn_iflags & JSITER_FOREACH))
+                 !(pn->pn_iflags & JSITER_FOREACH) &&
+                 !forOf)
                 ? (!pn1->isKind(PNK_ARRAY) || pn1->pn_count != 2)
                 : (!pn1->isKind(PNK_ARRAY) && !pn1->isKind(PNK_OBJECT))) &&
 #endif
                !pn1->isKind(PNK_CALL) &&
 #if JS_HAS_XML_SUPPORT
                !pn1->isKind(PNK_XMLUNARY) &&
 #endif
                !pn1->isKind(PNK_ELEM)))
@@ -3234,17 +3236,17 @@ Parser::forStatement()
           case PNK_ARRAY:
           case PNK_OBJECT:
             if (versionNumber() == JSVERSION_1_7) {
                 /*
                  * Destructuring for-in requires [key, value] enumeration
                  * in JS1.7.
                  */
                 JS_ASSERT(pn->isOp(JSOP_ITER));
-                if (!(pn->pn_iflags & JSITER_FOREACH))
+                if (!(pn->pn_iflags & JSITER_FOREACH) && !forOf)
                     pn->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           default:;
         }
 
@@ -5235,27 +5237,29 @@ Parser::comprehensionTail(ParseNode *kid
 
         switch (tt) {
 #if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             if (!CheckDestructuring(context, &data, pn3, this))
                 return NULL;
 
-            if (versionNumber() == JSVERSION_1_7) {
+            if (versionNumber() == JSVERSION_1_7 &&
+                !(pn2->pn_iflags & JSITER_FOREACH) &&
+                !forOf)
+            {
                 /* Destructuring requires [key, value] enumeration in JS1.7. */
                 if (!pn3->isKind(PNK_ARRAY) || pn3->pn_count != 2) {
                     reportError(NULL, JSMSG_BAD_FOR_LEFTSIDE);
                     return NULL;
                 }
 
                 JS_ASSERT(pn2->isOp(JSOP_ITER));
                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
-                if (!(pn2->pn_iflags & JSITER_FOREACH))
-                    pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
+                pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           case TOK_NAME:
             data.pn = pn3;
             if (!data.binder(context, &data, name, this))
                 return NULL;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/bug-728079-js17-1.js
@@ -0,0 +1,23 @@
+// for-of does not trigger the JS 1.7 for-in destructuring special case.
+
+version(170);
+
+var data = [[1, 2, 3], [4, 5, 6, 7]];
+
+function test(vars, expr, result) {
+    var s = '';
+    eval("for (" + vars + " of data) s += (" + expr + ") + ';';");
+    assertEq(s, result);
+}
+
+for (var prefix of ["var ", "let ", ""]) {
+    test(prefix + "[a, b, c]",
+         "a + ',' + b + ',' + c",
+         "1,2,3;4,5,6;");
+}
+
+test("var [a]", "a", "1;4;");
+test("var {length: len}", "len", "3;4;");
+test("var {length}", "length", "3;4;");
+test("{}", "0", "0;0;");
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/bug-728079-js17-2.js
@@ -0,0 +1,15 @@
+// for-of in comprehensions does not trigger the JS 1.7 for-in destructuring special case.
+
+version(170);
+load(libdir + "asserts.js");
+
+var data = [[1, 2, 3], [4]];
+var arr = eval("[a for ([a] of data)]");
+assertEq(arr.length, 2);
+assertEq(arr[0], 1);
+assertEq(arr[1], 4);
+
+arr = eval("[length for ({length} of data)]");
+assertEq(arr.length, 2);
+assertEq(arr[0], 3);
+assertEq(arr[1], 1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/bug-728079-js17-3.js
@@ -0,0 +1,4 @@
+// Cleaned-up version of bug 728079 comment 0.
+
+version(170);
+eval("(function f() { return [[b, a] for ([a, b] of c.items())]; })");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/bug-728079-js17-4.js
@@ -0,0 +1,4 @@
+// Test case from bug 785989 comment 3.
+
+version(170);
+Reflect.parse("for (let [a, b] of c) ;");