summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/destructuring
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /js/src/tests/non262/destructuring
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/non262/destructuring')
-rw-r--r--js/src/tests/non262/destructuring/array-default-class.js25
-rw-r--r--js/src/tests/non262/destructuring/array-iterator-close.js93
-rw-r--r--js/src/tests/non262/destructuring/browser.js0
-rw-r--r--js/src/tests/non262/destructuring/bug1396261.js44
-rw-r--r--js/src/tests/non262/destructuring/constant-folding.js16
-rw-r--r--js/src/tests/non262/destructuring/cover-init-name-syntax.js72
-rw-r--r--js/src/tests/non262/destructuring/duplicate-__proto__.js54
-rw-r--r--js/src/tests/non262/destructuring/iterator-primitive.js36
-rw-r--r--js/src/tests/non262/destructuring/order-super.js701
-rw-r--r--js/src/tests/non262/destructuring/order.js719
-rw-r--r--js/src/tests/non262/destructuring/rest-parameter-aray-iterator.js40
-rw-r--r--js/src/tests/non262/destructuring/rest-parameter-arguments.js101
-rw-r--r--js/src/tests/non262/destructuring/rest-parameter-function-length.js41
-rw-r--r--js/src/tests/non262/destructuring/rest-parameter-spread-call-optimization.js29
-rw-r--r--js/src/tests/non262/destructuring/rest-parameter-syntax.js87
-rw-r--r--js/src/tests/non262/destructuring/rest-parameter.js54
-rw-r--r--js/src/tests/non262/destructuring/rest-with-trailing-comma.js45
-rw-r--r--js/src/tests/non262/destructuring/shell.js0
-rw-r--r--js/src/tests/non262/destructuring/yield-in-object-destr-function.js182
-rw-r--r--js/src/tests/non262/destructuring/yield-in-object-destr-generator.js200
-rw-r--r--js/src/tests/non262/destructuring/yield-in-object-destr-script.js123
-rw-r--r--js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-function.js182
-rw-r--r--js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-generator.js200
-rw-r--r--js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-script.js123
24 files changed, 3167 insertions, 0 deletions
diff --git a/js/src/tests/non262/destructuring/array-default-class.js b/js/src/tests/non262/destructuring/array-default-class.js
new file mode 100644
index 0000000000..5aa9c579b1
--- /dev/null
+++ b/js/src/tests/non262/destructuring/array-default-class.js
@@ -0,0 +1,25 @@
+var BUGNUMBER = 1322314;
+var summary = "Function in computed property in class expression in array destructuring default";
+
+print(BUGNUMBER + ": " + summary);
+
+function* g([
+ a = class E {
+ [ (function() { return "foo"; })() ]() {
+ return 10;
+ }
+ }
+]) {
+ yield a;
+}
+
+let C = [...g([])][0];
+let x = new C();
+assertEq(x.foo(), 10);
+
+C = [...g([undefined])][0];
+x = new C();
+assertEq(x.foo(), 10);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/array-iterator-close.js b/js/src/tests/non262/destructuring/array-iterator-close.js
new file mode 100644
index 0000000000..ed35135dba
--- /dev/null
+++ b/js/src/tests/non262/destructuring/array-iterator-close.js
@@ -0,0 +1,93 @@
+// Tests that IteratorClose is called in array destructuring patterns.
+
+function test() {
+ var returnCalled = 0;
+ var returnCalledExpected = 0;
+ var iterable = {};
+
+ // empty [] calls IteratorClose regardless of "done" on the result.
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ return { done: true };
+ },
+ ret: function() {
+ returnCalled++;
+ return {};
+ }
+ });
+ var [] = iterable;
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ return {};
+ }
+ });
+ var [] = iterable;
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // Non-empty destructuring calls IteratorClose if iterator is not done by
+ // the end of destructuring.
+ var [a,b] = iterable;
+ assertEq(returnCalled, ++returnCalledExpected);
+ var [c,] = iterable;
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in lhs ref calls IteratorClose
+ function throwlhs() {
+ throw "in lhs";
+ }
+ assertThrowsValue(function() {
+ 0, [...{}[throwlhs()]] = iterable;
+ }, "in lhs");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in lhs ref calls IteratorClose with falsy "done".
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ // "done" is undefined.
+ return {};
+ },
+ ret: function() {
+ returnCalled++;
+ return {};
+ }
+ });
+ assertThrowsValue(function() {
+ 0, [...{}[throwlhs()]] = iterable;
+ }, "in lhs");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in iter.next doesn't call IteratorClose
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ throw "in next";
+ },
+ ret: function() {
+ returnCalled++;
+ return {};
+ }
+ });
+ assertThrowsValue(function() {
+ var [d] = iterable;
+ }, "in next");
+ assertEq(returnCalled, returnCalledExpected);
+
+ // "return" must return an Object.
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ return 42;
+ }
+ });
+ assertThrowsInstanceOf(function() {
+ var [] = iterable;
+ }, TypeError);
+ assertEq(returnCalled, ++returnCalledExpected);
+}
+
+test();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/browser.js b/js/src/tests/non262/destructuring/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/destructuring/browser.js
diff --git a/js/src/tests/non262/destructuring/bug1396261.js b/js/src/tests/non262/destructuring/bug1396261.js
new file mode 100644
index 0000000000..5d16b09323
--- /dev/null
+++ b/js/src/tests/non262/destructuring/bug1396261.js
@@ -0,0 +1,44 @@
+// Ensure array or object literals with trailing property accessors are not
+// treated as nested destructuring patterns in assignment destructuring
+// contexts.
+
+// Array destructuring with normal element.
+[{a: 0}.x] = [];
+[[0].x] = [];
+
+// Array destructuring with spread element.
+[...{a: 0}.x] = [];
+[...[0].x] = [];
+
+// Object destructuring with normal property.
+({a: {b: 0}.x} = {});
+({a: [0].x} = {});
+
+// Object destructuring with spread property.
+({...{b: 0}.x} = {});
+({...[0].x} = {});
+
+// Object literal with initializer shorthand in destructuring context.
+assertThrowsInstanceOf(() => Function(`[{a = 0}.x] = [];`), SyntaxError);
+assertThrowsInstanceOf(() => Function(`[...{a = 0}.x] = [];`), SyntaxError);
+assertThrowsInstanceOf(() => Function(`({a: {b = 0}.x} = {});`), SyntaxError);
+assertThrowsInstanceOf(() => Function(`({...{b = 0}.x} = {});`), SyntaxError);
+
+// Object destructuring with "eval" or "arguments" shorthand in strict mode.
+(function() {
+ "use strict";
+
+ // Ensure "eval" resp. "arguments" is not treated as an assignment.
+ [{eval}.x] = [];
+ [...{eval}.x] = [];
+ ({a: {eval}.x} = {});
+ ({...{eval}.x} = {});
+
+ [{arguments}.x] = [];
+ [...{arguments}.x] = [];
+ ({a: {arguments}.x} = {});
+ ({...{arguments}.x} = {});
+})();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/constant-folding.js b/js/src/tests/non262/destructuring/constant-folding.js
new file mode 100644
index 0000000000..b5aa893215
--- /dev/null
+++ b/js/src/tests/non262/destructuring/constant-folding.js
@@ -0,0 +1,16 @@
+function assertSyntaxError(code) {
+ assertThrowsInstanceOf(function () { Function(code); }, SyntaxError, "Function:" + code);
+ assertThrowsInstanceOf(function () { eval(code); }, SyntaxError, "eval:" + code);
+ var ieval = eval;
+ assertThrowsInstanceOf(function () { ieval(code); }, SyntaxError, "indirect eval:" + code);
+}
+
+// |true && a| is constant-folded to |a|, ensure the destructuring assignment
+// validation takes place before constant-folding.
+for (let prefix of ["null,", "var", "let", "const"]) {
+ assertSyntaxError(`${prefix} [true && a] = [];`);
+ assertSyntaxError(`${prefix} {p: true && a} = {};`);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/destructuring/cover-init-name-syntax.js b/js/src/tests/non262/destructuring/cover-init-name-syntax.js
new file mode 100644
index 0000000000..b37d8c2904
--- /dev/null
+++ b/js/src/tests/non262/destructuring/cover-init-name-syntax.js
@@ -0,0 +1,72 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// CoverInitName in arrow parameters.
+({a = 1}, {b = 2}, {c = 3}) => {};
+({a = 1} = {}, {b = 2}, {c = 3}) => {};
+({a = 1} = {}, {b = 2} = {}, {c = 3}) => {};
+({a = 1} = {}, {b = 2} = {}, {c = 3} = {}) => {};
+
+
+// CoverInitName in CoverParenthesizedExpressionAndArrowParameterList,
+// but not ArrowParameters.
+assertThrowsInstanceOf(() => eval(`
+ ({a = 1}, {b = 2}, {c = 3});
+`), SyntaxError);
+assertThrowsInstanceOf(() => eval(`
+ ({a = 1}, {b = 2}, {c = 3} = {});
+`), SyntaxError);
+assertThrowsInstanceOf(() => eval(`
+ ({a = 1}, {b = 2} = {}, {c = 3} = {});
+`), SyntaxError);
+
+
+// CoverInitName nested in array destructuring.
+[{a = 0}] = [{}];
+var [{a = 0}] = [{}];
+{ let [{a = 0}] = [{}]; }
+{ const [{a = 0}] = [{}]; }
+
+for ([{a = 0}] of []);
+for (var [{a = 0}] of []);
+for (let [{a = 0}] of []);
+for (const [{a = 0}] of []);
+
+function f([{a = 0}]) {}
+var h = ([{a = 0}]) => {};
+
+
+// CoverInitName nested in rest pattern.
+[...[{a = 0}]] = [{}];
+var [...[{a = 0}]] = [{}];
+{ let [...[{a = 0}]] = [{}]; }
+{ const [...[{a = 0}]] = [{}]; }
+
+for ([...[{a = 0}]] of []);
+for (var [...[{a = 0}]] of []);
+for (let [...[{a = 0}]] of []);
+for (const [...[{a = 0}]] of []);
+
+function f([...[{a = 0}]]) {}
+var h = ([...[{a = 0}]]) => {};
+
+
+// CoverInitName nested in object destructuring.
+({p: {a = 0}} = {p: {}});
+var {p: {a = 0}} = {p: {}};
+{ let {p: {a = 0}} = {p: {}}; }
+{ const {p: {a = 0}} = {p: {}}; }
+
+for ({p: {a = 0}} of []);
+for (var {p: {a = 0}} of []);
+for (let {p: {a = 0}} of []);
+for (const {p: {a = 0}} of []);
+
+function f({p: {a = 0}}) {}
+var h = ({p: {a = 0}}) => {};
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/duplicate-__proto__.js b/js/src/tests/non262/destructuring/duplicate-__proto__.js
new file mode 100644
index 0000000000..a8f76014e9
--- /dev/null
+++ b/js/src/tests/non262/destructuring/duplicate-__proto__.js
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring assignment.
+var a, b;
+({__proto__: a, __proto__: b} = {});
+assertEq(a, Object.prototype);
+assertEq(b, Object.prototype);
+
+// Destructuring binding with "var".
+var {__proto__: a, __proto__: b} = {};
+assertEq(a, Object.prototype);
+assertEq(b, Object.prototype);
+
+// Destructuring binding with "let".
+{
+ let {__proto__: a, __proto__: b} = {};
+ assertEq(a, Object.prototype);
+ assertEq(b, Object.prototype);
+}
+
+// Destructuring binding with "const".
+{
+ const {__proto__: a, __proto__: b} = {};
+ assertEq(a, Object.prototype);
+ assertEq(b, Object.prototype);
+}
+
+// Function parameters.
+function f1({__proto__: a, __proto__: b}) {
+ assertEq(a, Object.prototype);
+ assertEq(b, Object.prototype);
+}
+f1({});
+
+// Arrow function parameters.
+var f2 = ({__proto__: a, __proto__: b}) => {
+ assertEq(a, Object.prototype);
+ assertEq(b, Object.prototype);
+};
+f2({});
+
+// Arrow function parameters with defaults (initially parsed as destructuring assignment).
+var f3 = ({__proto__: a, __proto__: b} = {}) => {
+ assertEq(a, Object.prototype);
+ assertEq(b, Object.prototype);
+};
+f3({});
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/iterator-primitive.js b/js/src/tests/non262/destructuring/iterator-primitive.js
new file mode 100644
index 0000000000..17d100367c
--- /dev/null
+++ b/js/src/tests/non262/destructuring/iterator-primitive.js
@@ -0,0 +1,36 @@
+var BUGNUMBER = 1021835;
+var summary = "Returning non-object from @@iterator should throw";
+
+print(BUGNUMBER + ": " + summary);
+
+let primitives = [
+ 1,
+ true,
+ undefined,
+ null,
+ "foo",
+ Symbol.iterator
+];
+
+function f([]) {
+}
+
+for (let primitive of primitives) {
+ let obj = {
+ [Symbol.iterator]() {
+ return primitive;
+ }
+ };
+ assertThrowsInstanceOf(() => {
+ let [] = obj;
+ }, TypeError);
+ assertThrowsInstanceOf(() => {
+ [] = obj;
+ }, TypeError);
+ assertThrowsInstanceOf(() => {
+ f(obj);
+ }, TypeError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/order-super.js b/js/src/tests/non262/destructuring/order-super.js
new file mode 100644
index 0000000000..2bc534e23f
--- /dev/null
+++ b/js/src/tests/non262/destructuring/order-super.js
@@ -0,0 +1,701 @@
+var BUGNUMBER = 1204028;
+var summary = "Destructuring should evaluate lhs reference before rhs in super property";
+
+if (typeof assertEq === "undefined") {
+ assertEq = function(a, b) {
+ if (a !== b)
+ throw new Error(`expected ${b}, got ${a}\n${new Error().stack}`);
+ };
+}
+
+print(BUGNUMBER + ": " + summary);
+
+let logs = [];
+function log(x) {
+ logs.push(x);
+}
+
+let unwrapMap = new Map();
+function unwrap(maybeWrapped) {
+ if (unwrapMap.has(maybeWrapped))
+ return unwrapMap.get(maybeWrapped);
+ return maybeWrapped;
+}
+function ToString(name) {
+ if (name == Symbol.iterator)
+ return "@@iterator";
+ return String(name);
+}
+function logger(obj, prefix=[]) {
+ let wrapped = new Proxy(obj, {
+ get(that, name) {
+ if (name == "return") {
+ // FIXME: Bug 1147371.
+ // We ignore IteratorClose for now.
+ return obj[name];
+ }
+
+ let names = prefix.concat(ToString(name));
+ log("rhs get " + names.join("::"));
+ let v = obj[name];
+ if (typeof v === "object" || typeof v === "function")
+ return logger(v, names);
+ return v;
+ },
+ apply(that, thisArg, args) {
+ let names = prefix.slice();
+ log("rhs call " + names.join("::"));
+ let v = obj.apply(unwrap(thisArg), args);
+ if (typeof v === "object" || typeof v === "function") {
+ names[names.length - 1] += "()";
+ return logger(v, names);
+ }
+ return v;
+ }
+ });
+ unwrapMap.set(wrapped, obj);
+ return wrapped;
+}
+
+class C1 {
+ constructor() {
+ this.clear();
+ }
+ clear() {
+ this.values = {};
+ }
+}
+for (let name of [
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
+ "0", "1", "length"
+]) {
+ Object.defineProperty(C1.prototype, name, {
+ set: function(value) {
+ log("lhs set " + name);
+ this.values[name] = value;
+ }
+ });
+}
+class C2 extends C1 {
+ constructor() {
+ super();
+
+ let clear = () => {
+ logs = [];
+ this.clear();
+ };
+
+ // Array.
+
+ clear();
+ [
+ super.a
+ ] = logger(["A"]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a, "A");
+
+ clear();
+ [
+ super[ (log("lhs before name a"), "a") ]
+ ] = logger(["A"]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before name a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a, "A");
+
+ // Array rest.
+
+ clear();
+ [
+ ...super.a
+ ] = logger(["A", "B", "C"]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a.join(","), "A,B,C");
+
+ clear();
+ [
+ ...super[ (log("lhs before name a"), "a") ]
+ ] = logger(["A", "B", "C"]);;
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before name a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a.join(","), "A,B,C");
+
+ // Array combined.
+
+ clear();
+ [
+ super.a,
+ super[ (log("lhs before name b"), "b") ],
+ ...super[ (log("lhs before name c"), "c") ]
+ ] = logger(["A", "B", "C"]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+
+ "lhs before name b",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set b",
+
+ "lhs before name c",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "lhs set c",
+ ].join(","));
+ assertEq(this.values.a, "A");
+ assertEq(this.values.b, "B");
+ assertEq(this.values.c.join(","), "C");
+
+ // Object.
+
+ clear();
+ ({
+ a: super.a
+ } = logger({a: "A"}));
+ assertEq(logs.join(","),
+ [
+ "rhs get a",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a, "A");
+
+ clear();
+ ({
+ a: super[ (log("lhs before name a"), "a") ]
+ } = logger({a: "A"}));
+ assertEq(logs.join(","),
+ [
+ "lhs before name a",
+ "rhs get a",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a, "A");
+
+ // Object combined.
+
+ clear();
+ ({
+ a: super.a,
+ b: super[ (log("lhs before name b"), "b") ]
+ } = logger({a: "A", b: "B"}));
+ assertEq(logs.join(","),
+ [
+ "rhs get a",
+ "lhs set a",
+
+ "lhs before name b",
+ "rhs get b",
+ "lhs set b",
+ ].join(","));
+ assertEq(this.values.a, "A");
+ assertEq(this.values.b, "B");
+
+ // == Nested ==
+
+ // Array -> Array
+
+ clear();
+ [
+ [
+ super[ (log("lhs before name a"), "a") ],
+ ...super[ (log("lhs before name b"), "b") ]
+ ]
+ ] = logger([["A", "B"]]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before name a",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set a",
+
+ "lhs before name b",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "lhs set b",
+ ].join(","));
+ assertEq(this.values.a, "A");
+ assertEq(this.values.b.length, 1);
+ assertEq(this.values.b[0], "B");
+
+ // Array rest -> Array
+
+ clear();
+ [
+ ...[
+ super[ (log("lhs before name a"), "a") ],
+ ...super[ (log("lhs before name b"), "b") ]
+ ]
+ ] = logger(["A", "B"]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+
+ "lhs before name a",
+ "lhs set a",
+
+ "lhs before name b",
+ "lhs set b",
+ ].join(","));
+ assertEq(this.values.a, "A");
+ assertEq(this.values.b.join(","), "B");
+
+ // Array -> Object
+ clear();
+ [
+ {
+ a: super[ (log("lhs before name a"), "a") ]
+ }
+ ] = logger([{a: "A"}]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+
+ "lhs before name a",
+ "rhs get @@iterator()::next()::value::a",
+ "lhs set a",
+ ].join(","));
+ assertEq(this.values.a, "A");
+
+ // Array rest -> Object
+ clear();
+ [
+ ...{
+ 0: super[ (log("lhs before name 0"), "0") ],
+ 1: super[ (log("lhs before name 1"), "1") ],
+ length: super[ (log("lhs before name length"), "length") ],
+ }
+ ] = logger(["A", "B"]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+
+ "lhs before name 0",
+ "lhs set 0",
+
+ "lhs before name 1",
+ "lhs set 1",
+
+ "lhs before name length",
+ "lhs set length",
+ ].join(","));
+ assertEq(this.values["0"], "A");
+ assertEq(this.values["1"], "B");
+ assertEq(this.values.length, 2);
+
+ // Object -> Array
+ clear();
+ ({
+ a: [
+ super[ (log("lhs before name b"), "b") ]
+ ]
+ } = logger({a: ["B"]}));
+ assertEq(logs.join(","),
+ [
+ "rhs get a",
+ "rhs get a::@@iterator",
+ "rhs call a::@@iterator",
+ "rhs get a::@@iterator()::next",
+
+ "lhs before name b",
+ "rhs call a::@@iterator()::next",
+ "rhs get a::@@iterator()::next()::done",
+ "rhs get a::@@iterator()::next()::value",
+ "lhs set b",
+ ].join(","));
+ assertEq(this.values.b, "B");
+
+ // Object -> Object
+ clear();
+ ({
+ a: {
+ b: super[ (log("lhs before name b"), "b") ]
+ }
+ } = logger({a: {b: "B"}}));
+ assertEq(logs.join(","),
+ [
+ "rhs get a",
+ "lhs before name b",
+ "rhs get a::b",
+ "lhs set b",
+ ].join(","));
+ assertEq(this.values.b, "B");
+
+ // All combined
+
+ clear();
+ [
+ super[ (log("lhs before name a"), "a") ],
+ [
+ super[ (log("lhs before name b"), "b") ],
+ {
+ c: super[ (log("lhs before name c"), "c") ],
+ d: {
+ e: super[ (log("lhs before name e"), "e") ],
+ f: [
+ super[ (log("lhs before name g"), "g") ]
+ ]
+ }
+ }
+ ],
+ {
+ h: super[ (log("lhs before name h"), "h") ],
+ i: [
+ super[ (log("lhs before name j"), "j") ],
+ {
+ k: [
+ super[ (log("lhs before name l"), "l") ]
+ ]
+ }
+ ]
+ },
+ ...[
+ super[ (log("lhs before name m"), "m") ],
+ [
+ super[ (log("lhs before name n"), "n") ],
+ {
+ o: super[ (log("lhs before name o"), "o") ],
+ p: {
+ q: super[ (log("lhs before name q"), "q") ],
+ r: [
+ super[ (log("lhs before name s"), "s") ]
+ ]
+ }
+ }
+ ],
+ ...{
+ 0: super[ (log("lhs before name t"), "t") ],
+ 1: [
+ super[ (log("lhs before name u"), "u") ],
+ {
+ v: super[ (log("lhs before name v"), "v") ],
+ w: {
+ x: super[ (log("lhs before name x"), "x") ],
+ y: [
+ super[ (log("lhs before name z"), "z") ]
+ ]
+ }
+ }
+ ],
+ length: super[ (log("lhs before name length"), "length") ],
+ }
+ ]
+ ] = logger(["A",
+ ["B", {c: "C", d: {e: "E", f: ["G"]}}],
+ {h: "H", i: ["J", {k: ["L"]}]},
+ "M",
+ ["N", {o: "O", p: {q: "Q", r: ["S"]}}],
+ "T", ["U", {v: "V", w: {x: "X", y: ["Z"]}}]]);
+ assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before name a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before name b",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set b",
+
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+
+ "lhs before name c",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::c",
+ "lhs set c",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d",
+
+ "lhs before name e",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::e",
+ "lhs set e",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
+
+ "lhs before name g",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next()::value",
+ "lhs set g",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+
+ "lhs before name h",
+ "rhs get @@iterator()::next()::value::h",
+ "lhs set h",
+
+ "rhs get @@iterator()::next()::value::i",
+ "rhs get @@iterator()::next()::value::i::@@iterator",
+ "rhs call @@iterator()::next()::value::i::@@iterator",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next",
+
+ "lhs before name j",
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value",
+ "lhs set j",
+
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value",
+
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator",
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
+
+ "lhs before name l",
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next()::value",
+ "lhs set l",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+
+ "lhs before name m",
+ "lhs set m",
+
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before name n",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set n",
+
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+
+ "lhs before name o",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::o",
+ "lhs set o",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p",
+
+ "lhs before name q",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::q",
+ "lhs set q",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
+
+ "lhs before name s",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next()::value",
+ "lhs set s",
+
+ "lhs before name t",
+ "lhs set t",
+
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before name u",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set u",
+
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+
+ "lhs before name v",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::v",
+ "lhs set v",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w",
+
+ "lhs before name x",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::x",
+ "lhs set x",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
+
+ "lhs before name z",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next()::value",
+ "lhs set z",
+
+ "lhs before name length",
+ "lhs set length",
+ ].join(","));
+ assertEq(this.values.a, "A");
+ assertEq(this.values.b, "B");
+ assertEq(this.values.c, "C");
+ assertEq(this.values.e, "E");
+ assertEq(this.values.g, "G");
+ assertEq(this.values.h, "H");
+ assertEq(this.values.j, "J");
+ assertEq(this.values.l, "L");
+ assertEq(this.values.m, "M");
+ assertEq(this.values.n, "N");
+ assertEq(this.values.o, "O");
+ assertEq(this.values.q, "Q");
+ assertEq(this.values.s, "S");
+ assertEq(this.values.t, "T");
+ assertEq(this.values.u, "U");
+ assertEq(this.values.v, "V");
+ assertEq(this.values.x, "X");
+ assertEq(this.values.z, "Z");
+ assertEq(this.values.length, 2);
+ }
+}
+
+new C2();
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/destructuring/order.js b/js/src/tests/non262/destructuring/order.js
new file mode 100644
index 0000000000..4da0a58512
--- /dev/null
+++ b/js/src/tests/non262/destructuring/order.js
@@ -0,0 +1,719 @@
+var BUGNUMBER = 1204028;
+var summary = "Destructuring should evaluate lhs reference before rhs";
+
+print(BUGNUMBER + ": " + summary);
+
+let storage = {
+ clear() {
+ this.values = {};
+ }
+};
+storage.clear();
+let obj = new Proxy(storage, {
+ set(that, name, value) {
+ log("lhs set " + name);
+ storage.values[name] = value;
+ }
+});
+
+let logs = [];
+function log(x) {
+ logs.push(x);
+}
+
+function clear() {
+ logs = [];
+ storage.clear();
+}
+
+let unwrapMap = new Map();
+function unwrap(maybeWrapped) {
+ if (unwrapMap.has(maybeWrapped))
+ return unwrapMap.get(maybeWrapped);
+ return maybeWrapped;
+}
+function ToString(name) {
+ if (name == Symbol.iterator)
+ return "@@iterator";
+ return String(name);
+}
+function logger(obj, prefix=[]) {
+ let wrapped = new Proxy(obj, {
+ get(that, name) {
+ if (name == "return") {
+ // FIXME: Bug 1147371.
+ // We ignore IteratorClose for now.
+ return obj[name];
+ }
+
+ let names = prefix.concat(ToString(name));
+ log("rhs get " + names.join("::"));
+ let v = obj[name];
+ if (typeof v === "object" || typeof v === "function")
+ return logger(v, names);
+ return v;
+ },
+ apply(that, thisArg, args) {
+ let names = prefix.slice();
+ log("rhs call " + names.join("::"));
+ let v = obj.apply(unwrap(thisArg), args);
+ if (typeof v === "object" || typeof v === "function") {
+ names[names.length - 1] += "()";
+ return logger(v, names);
+ }
+ return v;
+ }
+ });
+ unwrapMap.set(wrapped, obj);
+ return wrapped;
+}
+
+// Array.
+
+clear();
+[
+ ( log("lhs before obj a"), obj ).a
+] = logger(["A"]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before obj a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a, "A");
+
+clear();
+[
+ ( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ]
+] = logger(["A"]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a, "A");
+
+// Array rest.
+
+clear();
+[
+ ...( log("lhs before obj a"), obj ).a
+] = logger(["A", "B", "C"]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before obj a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a.join(","), "A,B,C");
+
+clear();
+[
+ ...( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ]
+] = logger(["A", "B", "C"]);;
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a.join(","), "A,B,C");
+
+// Array combined.
+
+clear();
+[
+ ( log("lhs before obj a"), obj ).a,
+ ( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ],
+ ...( log("lhs before obj c"), obj )[ (log("lhs before name c"), "c") ]
+] = logger(["A", "B", "C"]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before obj a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set b",
+
+ "lhs before obj c",
+ "lhs before name c",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "lhs set c",
+ ].join(","));
+assertEq(storage.values.a, "A");
+assertEq(storage.values.b, "B");
+assertEq(storage.values.c.join(","), "C");
+
+// Object.
+
+clear();
+({
+ a: ( log("lhs before obj a"), obj ).a
+} = logger({a: "A"}));
+assertEq(logs.join(","),
+ [
+ "lhs before obj a",
+ "rhs get a",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a, "A");
+
+clear();
+({
+ a: ( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ]
+} = logger({a: "A"}));
+assertEq(logs.join(","),
+ [
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs get a",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a, "A");
+
+// Object combined.
+
+clear();
+({
+ a: ( log("lhs before obj a"), obj ).a,
+ b: ( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ]
+} = logger({a: "A", b: "B"}));
+assertEq(logs.join(","),
+ [
+ "lhs before obj a",
+ "rhs get a",
+ "lhs set a",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs get b",
+ "lhs set b",
+ ].join(","));
+assertEq(storage.values.a, "A");
+assertEq(storage.values.b, "B");
+
+// == Nested ==
+
+// Array -> Array
+
+clear();
+[
+ [
+ ( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ],
+ ...( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ]
+ ]
+] = logger([["A", "B"]]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set a",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "lhs set b",
+ ].join(","));
+assertEq(storage.values.a, "A");
+assertEq(storage.values.b.length, 1);
+assertEq(storage.values.b[0], "B");
+
+// Array rest -> Array
+
+clear();
+[
+ ...[
+ ( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ],
+ ...( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ]
+ ]
+] = logger(["A", "B"]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "lhs set a",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "lhs set b",
+ ].join(","));
+assertEq(storage.values.a, "A");
+assertEq(storage.values.b.join(","), "B");
+
+// Array -> Object
+clear();
+[
+ {
+ a: ( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ]
+ }
+] = logger([{a: "A"}]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs get @@iterator()::next()::value::a",
+ "lhs set a",
+ ].join(","));
+assertEq(storage.values.a, "A");
+
+// Array rest -> Object
+clear();
+[
+ ...{
+ 0: ( log("lhs before obj 0"), obj )[ (log("lhs before name 0"), "0") ],
+ 1: ( log("lhs before obj 1"), obj )[ (log("lhs before name 1"), "1") ],
+ length: ( log("lhs before obj length"), obj )[ (log("lhs before name length"), "length") ],
+ }
+] = logger(["A", "B"]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+
+ "lhs before obj 0",
+ "lhs before name 0",
+ "lhs set 0",
+
+ "lhs before obj 1",
+ "lhs before name 1",
+ "lhs set 1",
+
+ "lhs before obj length",
+ "lhs before name length",
+ "lhs set length",
+ ].join(","));
+assertEq(storage.values["0"], "A");
+assertEq(storage.values["1"], "B");
+assertEq(storage.values.length, 2);
+
+// Object -> Array
+clear();
+({
+ a: [
+ ( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ]
+ ]
+} = logger({a: ["B"]}));
+assertEq(logs.join(","),
+ [
+ "rhs get a",
+ "rhs get a::@@iterator",
+ "rhs call a::@@iterator",
+ "rhs get a::@@iterator()::next",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs call a::@@iterator()::next",
+ "rhs get a::@@iterator()::next()::done",
+ "rhs get a::@@iterator()::next()::value",
+ "lhs set b",
+ ].join(","));
+assertEq(storage.values.b, "B");
+
+// Object -> Object
+clear();
+({
+ a: {
+ b: ( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ]
+ }
+} = logger({a: {b: "B"}}));
+assertEq(logs.join(","),
+ [
+ "rhs get a",
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs get a::b",
+ "lhs set b",
+ ].join(","));
+assertEq(storage.values.b, "B");
+
+// All combined
+
+clear();
+[
+ ( log("lhs before obj a"), obj )[ (log("lhs before name a"), "a") ],
+ [
+ ( log("lhs before obj b"), obj )[ (log("lhs before name b"), "b") ],
+ {
+ c: ( log("lhs before obj c"), obj )[ (log("lhs before name c"), "c") ],
+ d: {
+ e: ( log("lhs before obj e"), obj )[ (log("lhs before name e"), "e") ],
+ f: [
+ ( log("lhs before obj g"), obj )[ (log("lhs before name g"), "g") ]
+ ]
+ }
+ }
+ ],
+ {
+ h: ( log("lhs before obj h"), obj )[ (log("lhs before name h"), "h") ],
+ i: [
+ ( log("lhs before obj j"), obj )[ (log("lhs before name j"), "j") ],
+ {
+ k: [
+ ( log("lhs before obj l"), obj )[ (log("lhs before name l"), "l") ]
+ ]
+ }
+ ]
+ },
+ ...[
+ ( log("lhs before obj m"), obj )[ (log("lhs before name m"), "m") ],
+ [
+ ( log("lhs before obj n"), obj )[ (log("lhs before name n"), "n") ],
+ {
+ o: ( log("lhs before obj o"), obj )[ (log("lhs before name o"), "o") ],
+ p: {
+ q: ( log("lhs before obj q"), obj )[ (log("lhs before name q"), "q") ],
+ r: [
+ ( log("lhs before obj s"), obj )[ (log("lhs before name s"), "s") ]
+ ]
+ }
+ }
+ ],
+ ...{
+ 0: ( log("lhs before obj t"), obj )[ (log("lhs before name t"), "t") ],
+ 1: [
+ ( log("lhs before obj u"), obj )[ (log("lhs before name u"), "u") ],
+ {
+ v: ( log("lhs before obj v"), obj )[ (log("lhs before name v"), "v") ],
+ w: {
+ x: ( log("lhs before obj x"), obj )[ (log("lhs before name x"), "x") ],
+ y: [
+ ( log("lhs before obj z"), obj )[ (log("lhs before name z"), "z") ]
+ ]
+ }
+ }
+ ],
+ length: ( log("lhs before obj length"), obj )[ (log("lhs before name length"), "length") ],
+ }
+ ]
+] = logger(["A",
+ ["B", {c: "C", d: {e: "E", f: ["G"]}}],
+ {h: "H", i: ["J", {k: ["L"]}]},
+ "M",
+ ["N", {o: "O", p: {q: "Q", r: ["S"]}}],
+ "T", ["U", {v: "V", w: {x: "X", y: ["Z"]}}]]);
+assertEq(logs.join(","),
+ [
+ "rhs get @@iterator",
+ "rhs call @@iterator",
+ "rhs get @@iterator()::next",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set b",
+
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+
+ "lhs before obj c",
+ "lhs before name c",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::c",
+ "lhs set c",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d",
+
+ "lhs before obj e",
+ "lhs before name e",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::e",
+ "lhs set e",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
+
+ "lhs before obj g",
+ "lhs before name g",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next()::value",
+ "lhs set g",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+
+ "lhs before obj h",
+ "lhs before name h",
+ "rhs get @@iterator()::next()::value::h",
+ "lhs set h",
+
+ "rhs get @@iterator()::next()::value::i",
+ "rhs get @@iterator()::next()::value::i::@@iterator",
+ "rhs call @@iterator()::next()::value::i::@@iterator",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next",
+
+ "lhs before obj j",
+ "lhs before name j",
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value",
+ "lhs set j",
+
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value",
+
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator",
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
+
+ "lhs before obj l",
+ "lhs before name l",
+ "rhs call @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next()::value",
+ "lhs set l",
+
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+
+ "lhs before obj m",
+ "lhs before name m",
+ "lhs set m",
+
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before obj n",
+ "lhs before name n",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set n",
+
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+
+ "lhs before obj o",
+ "lhs before name o",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::o",
+ "lhs set o",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p",
+
+ "lhs before obj q",
+ "lhs before name q",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::q",
+ "lhs set q",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
+
+ "lhs before obj s",
+ "lhs before name s",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next()::value",
+ "lhs set s",
+
+ "lhs before obj t",
+ "lhs before name t",
+ "lhs set t",
+
+ "rhs get @@iterator()::next()::value::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+
+ "lhs before obj u",
+ "lhs before name u",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "lhs set u",
+
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+
+ "lhs before obj v",
+ "lhs before name v",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::v",
+ "lhs set v",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w",
+
+ "lhs before obj x",
+ "lhs before name x",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::x",
+ "lhs set x",
+
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
+
+ "lhs before obj z",
+ "lhs before name z",
+ "rhs call @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next()::value",
+ "lhs set z",
+
+ "lhs before obj length",
+ "lhs before name length",
+ "lhs set length",
+ ].join(","));
+assertEq(storage.values.a, "A");
+assertEq(storage.values.b, "B");
+assertEq(storage.values.c, "C");
+assertEq(storage.values.e, "E");
+assertEq(storage.values.g, "G");
+assertEq(storage.values.h, "H");
+assertEq(storage.values.j, "J");
+assertEq(storage.values.l, "L");
+assertEq(storage.values.m, "M");
+assertEq(storage.values.n, "N");
+assertEq(storage.values.o, "O");
+assertEq(storage.values.q, "Q");
+assertEq(storage.values.s, "S");
+assertEq(storage.values.t, "T");
+assertEq(storage.values.u, "U");
+assertEq(storage.values.v, "V");
+assertEq(storage.values.x, "X");
+assertEq(storage.values.z, "Z");
+assertEq(storage.values.length, 2);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/destructuring/rest-parameter-aray-iterator.js b/js/src/tests/non262/destructuring/rest-parameter-aray-iterator.js
new file mode 100644
index 0000000000..bf9643fd78
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-parameter-aray-iterator.js
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Destructuring rest arrays call the array iterator. This behaviour is
+// observable when Array.prototype[Symbol.iterator] is overridden.
+
+const oldArrayIterator = Array.prototype[Symbol.iterator];
+try {
+ let callCount = 0;
+ Array.prototype[Symbol.iterator] = function() {
+ callCount += 1;
+ return oldArrayIterator.call(this);
+ };
+
+ // Array iterator called exactly once.
+ function arrayIterCalledOnce(...[]) { }
+ assertEq(callCount, 0);
+ arrayIterCalledOnce();
+ assertEq(callCount, 1);
+
+ // Array iterator not called before rest parameter.
+ callCount = 0;
+ function arrayIterNotCalledBeforeRest(t = assertEq(callCount, 0), ...[]) { }
+ assertEq(callCount, 0);
+ arrayIterNotCalledBeforeRest();
+ assertEq(callCount, 1);
+
+ // Array iterator called when rest parameter is processed.
+ callCount = 0;
+ function arrayIterCalledWhenDestructuring(...[t = assertEq(callCount, 1)]) { }
+ assertEq(callCount, 0);
+ arrayIterCalledWhenDestructuring();
+ assertEq(callCount, 1);
+} finally {
+ Array.prototype[Symbol.iterator] = oldArrayIterator;
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/rest-parameter-arguments.js b/js/src/tests/non262/destructuring/rest-parameter-arguments.js
new file mode 100644
index 0000000000..e87cdff339
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-parameter-arguments.js
@@ -0,0 +1,101 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Ensure the |arguments| object works as expected when a destructuring rest
+// parameter is present.
+
+// |arguments.length| with destructuring rest array.
+function argsLengthEmptyRestArray(...[]) {
+ return arguments.length;
+}
+assertEq(argsLengthEmptyRestArray(), 0);
+assertEq(argsLengthEmptyRestArray(10), 1);
+assertEq(argsLengthEmptyRestArray(10, 20), 2);
+
+function argsLengthRestArray(...[a]) {
+ return arguments.length;
+}
+assertEq(argsLengthRestArray(), 0);
+assertEq(argsLengthRestArray(10), 1);
+assertEq(argsLengthRestArray(10, 20), 2);
+
+function argsLengthRestArrayWithDefault(...[a = 0]) {
+ return arguments.length;
+}
+assertEq(argsLengthRestArrayWithDefault(), 0);
+assertEq(argsLengthRestArrayWithDefault(10), 1);
+assertEq(argsLengthRestArrayWithDefault(10, 20), 2);
+
+
+// |arguments.length| with destructuring rest object.
+function argsLengthEmptyRestObject(...{}) {
+ return arguments.length;
+}
+assertEq(argsLengthEmptyRestObject(), 0);
+assertEq(argsLengthEmptyRestObject(10), 1);
+assertEq(argsLengthEmptyRestObject(10, 20), 2);
+
+function argsLengthRestObject(...{a}) {
+ return arguments.length;
+}
+assertEq(argsLengthRestObject(), 0);
+assertEq(argsLengthRestObject(10), 1);
+assertEq(argsLengthRestObject(10, 20), 2);
+
+function argsLengthRestObjectWithDefault(...{a = 0}) {
+ return arguments.length;
+}
+assertEq(argsLengthRestObjectWithDefault(), 0);
+assertEq(argsLengthRestObjectWithDefault(10), 1);
+assertEq(argsLengthRestObjectWithDefault(10, 20), 2);
+
+
+// |arguments| access with destructuring rest array.
+function argsAccessEmptyRestArray(...[]) {
+ return arguments[0];
+}
+assertEq(argsAccessEmptyRestArray(), undefined);
+assertEq(argsAccessEmptyRestArray(10), 10);
+assertEq(argsAccessEmptyRestArray(10, 20), 10);
+
+function argsAccessRestArray(...[a]) {
+ return arguments[0];
+}
+assertEq(argsAccessRestArray(), undefined);
+assertEq(argsAccessRestArray(10), 10);
+assertEq(argsAccessRestArray(10, 20), 10);
+
+function argsAccessRestArrayWithDefault(...[a = 0]) {
+ return arguments[0];
+}
+assertEq(argsAccessRestArrayWithDefault(), undefined);
+assertEq(argsAccessRestArrayWithDefault(10), 10);
+assertEq(argsAccessRestArrayWithDefault(10, 20), 10);
+
+
+// |arguments| access with destructuring rest object.
+function argsAccessEmptyRestObject(...{}) {
+ return arguments[0];
+}
+assertEq(argsAccessEmptyRestObject(), undefined);
+assertEq(argsAccessEmptyRestObject(10), 10);
+assertEq(argsAccessEmptyRestObject(10, 20), 10);
+
+function argsAccessRestObject(...{a}) {
+ return arguments[0];
+}
+assertEq(argsAccessRestObject(), undefined);
+assertEq(argsAccessRestObject(10), 10);
+assertEq(argsAccessRestObject(10, 20), 10);
+
+function argsAccessRestObjectWithDefault(...{a = 0}) {
+ return arguments[0];
+}
+assertEq(argsAccessRestObjectWithDefault(), undefined);
+assertEq(argsAccessRestObjectWithDefault(10), 10);
+assertEq(argsAccessRestObjectWithDefault(10, 20), 10);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/rest-parameter-function-length.js b/js/src/tests/non262/destructuring/rest-parameter-function-length.js
new file mode 100644
index 0000000000..5924e799ad
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-parameter-function-length.js
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Ensure function length is set correctly when a destructuring rest parameter
+// is present.
+
+assertEq(function(...[]) {}.length, 0);
+assertEq(function(...[a]) {}.length, 0);
+assertEq(function(...[a = 0]) {}.length, 0);
+assertEq(function(...{}) {}.length, 0);
+assertEq(function(...{p: a}) {}.length, 0);
+assertEq(function(...{p: a = 0}) {}.length, 0);
+assertEq(function(...{a = 0}) {}.length, 0);
+
+assertEq(function(x, ...[]) {}.length, 1);
+assertEq(function(x, ...[a]) {}.length, 1);
+assertEq(function(x, ...[a = 0]) {}.length, 1);
+assertEq(function(x, ...{}) {}.length, 1);
+assertEq(function(x, ...{p: a}) {}.length, 1);
+assertEq(function(x, ...{p: a = 0}) {}.length, 1);
+assertEq(function(x, ...{a = 0}) {}.length, 1);
+
+assertEq(function(x, y, ...[]) {}.length, 2);
+assertEq(function(x, y, ...[a]) {}.length, 2);
+assertEq(function(x, y, ...[a = 0]) {}.length, 2);
+assertEq(function(x, y, ...{}) {}.length, 2);
+assertEq(function(x, y, ...{p: a}) {}.length, 2);
+assertEq(function(x, y, ...{p: a = 0}) {}.length, 2);
+assertEq(function(x, y, ...{a = 0}) {}.length, 2);
+
+assertEq(function(x, y = 0, ...[]) {}.length, 1);
+assertEq(function(x, y = 0, ...[a]) {}.length, 1);
+assertEq(function(x, y = 0, ...[a = 0]) {}.length, 1);
+assertEq(function(x, y = 0, ...{}) {}.length, 1);
+assertEq(function(x, y = 0, ...{p: a}) {}.length, 1);
+assertEq(function(x, y = 0, ...{p: a = 0}) {}.length, 1);
+assertEq(function(x, y = 0, ...{a = 0}) {}.length, 1);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/rest-parameter-spread-call-optimization.js b/js/src/tests/non262/destructuring/rest-parameter-spread-call-optimization.js
new file mode 100644
index 0000000000..20f6a529dc
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-parameter-spread-call-optimization.js
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Ensure the spread-call optimization doesn't break when a destructuring rest
+// parameter is used.
+
+function spreadTarget() { return arguments.length; }
+
+function spreadOpt(...[r]){ return spreadTarget(...r); }
+assertEq(spreadOpt([]), 0);
+assertEq(spreadOpt([10]), 1);
+assertEq(spreadOpt([10, 20]), 2);
+assertEq(spreadOpt([10, 20, 30]), 3);
+
+function spreadOpt2(...[...r]){ return spreadTarget(...r); }
+assertEq(spreadOpt2(), 0);
+assertEq(spreadOpt2(10), 1);
+assertEq(spreadOpt2(10, 20), 2);
+assertEq(spreadOpt2(10, 20, 30), 3);
+
+function spreadOpt3(r, ...[]){ return spreadTarget(...r); }
+assertEq(spreadOpt3([]), 0);
+assertEq(spreadOpt3([10]), 1);
+assertEq(spreadOpt3([10, 20]), 2);
+assertEq(spreadOpt3([10, 20, 30]), 3);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/rest-parameter-syntax.js b/js/src/tests/non262/destructuring/rest-parameter-syntax.js
new file mode 100644
index 0000000000..a145d1a2df
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-parameter-syntax.js
@@ -0,0 +1,87 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+const bindingPatterns = [
+ "[]",
+ "[a]",
+ "[a, b]",
+ "[a, ...b]",
+ "[...a]",
+ "[...[]]",
+
+ "{}",
+ "{p: a}",
+ "{p: a = 0}",
+ "{p: {}}",
+ "{p: a, q: b}",
+ "{a}",
+ "{a, b}",
+ "{a = 0}",
+];
+
+const functions = [
+ p => `function f(${p}) {}`,
+ p => `function* g(${p}) {}`,
+ p => `({m(${p}) {}});`,
+ p => `(class {m(${p}) {}});`,
+ p => `(${p}) => {};`,
+];
+
+for (let pattern of bindingPatterns) {
+ for (let fn of functions) {
+ // No leading parameters.
+ eval(fn(`...${pattern}`));
+
+ // Leading normal parameters.
+ eval(fn(`x, ...${pattern}`));
+ eval(fn(`x, y, ...${pattern}`));
+
+ // Leading parameters with defaults.
+ eval(fn(`x = 0, ...${pattern}`));
+ eval(fn(`x = 0, y = 0, ...${pattern}`));
+
+ // Leading array destructuring parameters.
+ eval(fn(`[], ...${pattern}`));
+ eval(fn(`[x], ...${pattern}`));
+ eval(fn(`[x = 0], ...${pattern}`));
+ eval(fn(`[...x], ...${pattern}`));
+
+ // Leading object destructuring parameters.
+ eval(fn(`{}, ...${pattern}`));
+ eval(fn(`{p: x}, ...${pattern}`));
+ eval(fn(`{x}, ...${pattern}`));
+ eval(fn(`{x = 0}, ...${pattern}`));
+
+ // Trailing parameters after rest parameter.
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern},`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern}, x`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern}, x = 0`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern}, ...x`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern}, []`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern}, {}`)), SyntaxError);
+
+ // Rest parameter with defaults.
+ assertThrowsInstanceOf(() => eval(fn(`...${pattern} = 0`)), SyntaxError);
+ }
+}
+
+for (let fn of functions) {
+ // Missing name, incomplete patterns.
+ assertThrowsInstanceOf(() => eval(fn(`...`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...[`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...{`)), SyntaxError);
+
+ // Invalid binding name.
+ assertThrowsInstanceOf(() => eval(fn(`...[0]`)), SyntaxError);
+ assertThrowsInstanceOf(() => eval(fn(`...[p.q]`)), SyntaxError);
+}
+
+// Rest parameters aren't valid in getter/setter methods.
+assertThrowsInstanceOf(() => eval(`({get p(...[]) {}})`), SyntaxError);
+assertThrowsInstanceOf(() => eval(`({set p(...[]) {}})`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/rest-parameter.js b/js/src/tests/non262/destructuring/rest-parameter.js
new file mode 100644
index 0000000000..50d77f3cc5
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-parameter.js
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Simple functional test for destructuring rest parameters.
+
+function arrayRest(...[a, b]) {
+ return a + b;
+}
+assertEq(arrayRest(3, 7), 10);
+
+
+function arrayRestWithDefault(...[a, b = 1]) {
+ return a + b;
+}
+assertEq(arrayRestWithDefault(3, 7), 10);
+assertEq(arrayRestWithDefault(4), 5);
+assertEq(arrayRestWithDefault(4, undefined), 5);
+
+
+function objectRest(...{length: len}) {
+ return len;
+}
+assertEq(objectRest(), 0);
+assertEq(objectRest(10), 1);
+assertEq(objectRest(10, 20), 2);
+
+
+function objectRestWithDefault(...{0: a, 1: b = 1}) {
+ return a + b;
+}
+assertEq(objectRestWithDefault(3, 7), 10);
+assertEq(objectRestWithDefault(4), 5);
+assertEq(objectRestWithDefault(4, undefined), 5);
+
+
+function arrayRestWithNestedRest(...[...r]) {
+ return r.length;
+}
+assertEq(arrayRestWithNestedRest(), 0);
+assertEq(arrayRestWithNestedRest(10), 1);
+assertEq(arrayRestWithNestedRest(10, 20), 2);
+
+
+function arrayRestTDZ(...[a = a]) { }
+assertThrowsInstanceOf(() => arrayRestTDZ(), ReferenceError);
+
+
+function objectRestTDZ(...{a = a}) { }
+assertThrowsInstanceOf(() => objectRestTDZ(), ReferenceError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/rest-with-trailing-comma.js b/js/src/tests/non262/destructuring/rest-with-trailing-comma.js
new file mode 100644
index 0000000000..310180e14b
--- /dev/null
+++ b/js/src/tests/non262/destructuring/rest-with-trailing-comma.js
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const invalidSyntax = [
+ "[...r, ]",
+ "[a, ...r, ]",
+ "[a = 0, ...r, ]",
+ "[[], ...r, ]",
+ "[[...r,]]",
+ "[[...r,], ]",
+ "[[...r,], a]",
+];
+
+const validSyntax = [
+ "[, ]",
+ "[a, ]",
+ "[[], ]",
+];
+
+const destructuringForms = [
+ a => `${a} = [];`,
+ a => `var ${a} = [];`,
+ a => `let ${a} = [];`,
+ a => `const ${a} = [];`,
+ a => `(${a}) => {};`,
+ a => `(${a} = []) => {};`,
+ a => `function f(${a}) {}`,
+];
+
+for (let invalid of invalidSyntax) {
+ for (let fn of destructuringForms) {
+ assertThrowsInstanceOf(() => Function(fn(invalid)), SyntaxError);
+ }
+}
+
+for (let invalid of validSyntax) {
+ for (let fn of destructuringForms) {
+ Function(fn(invalid));
+ }
+}
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/destructuring/shell.js b/js/src/tests/non262/destructuring/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/destructuring/shell.js
diff --git a/js/src/tests/non262/destructuring/yield-in-object-destr-function.js b/js/src/tests/non262/destructuring/yield-in-object-destr-function.js
new file mode 100644
index 0000000000..9f5eed8345
--- /dev/null
+++ b/js/src/tests/non262/destructuring/yield-in-object-destr-function.js
@@ -0,0 +1,182 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring binding patterns with var.
+(function() {
+ var {a: yield} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+
+ var {yield} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+
+ var {yield = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ var {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ var {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ var {yield = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with let.
+(function(){
+ let {a: yield} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+})();
+
+(function() {
+ let {yield} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+})();
+
+(function() {
+ let {yield = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ let {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ let {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ let {yield = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with const.
+(function() {
+ const {a: yield} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+})();
+
+(function() {
+ const {yield} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+})();
+
+(function() {
+ const {yield = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ const {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ const {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ const {yield = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns in parameters.
+(function({a: yield} = {a: "yield-with-name"}) {
+ assertEq(yield, "yield-with-name");
+})();
+
+(function({yield} = {yield: "yield-with-shorthand"}) {
+ assertEq(yield, "yield-with-shorthand");
+})();
+
+(function({yield = 0} = {yield: "yield-with-coverinitname"}) {
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f({a: yield} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f({yield} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f({yield = 0} = {}) { }
+`), SyntaxError);
+
+
+// Destructuring assignment pattern.
+(function() {
+ var a, yield;
+
+ ({a: yield} = {a: "yield-with-name"});
+ assertEq(yield, "yield-with-name");
+
+ ({yield} = {yield: "yield-with-shorthand"});
+ assertEq(yield, "yield-with-shorthand");
+
+ ({yield = 0} = {yield: "yield-with-coverinitname"});
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ ({a: yield} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ ({yield} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function f() {
+ ({yield = 0} = {});
+ }
+`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/destructuring/yield-in-object-destr-generator.js b/js/src/tests/non262/destructuring/yield-in-object-destr-generator.js
new file mode 100644
index 0000000000..4423f8190f
--- /dev/null
+++ b/js/src/tests/non262/destructuring/yield-in-object-destr-generator.js
@@ -0,0 +1,200 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring binding patterns with var.
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ var {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ var {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ var {yield = 0} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ var {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ var {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ var {yield = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with let.
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ let {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ let {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ let {yield = 0} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ let {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ let {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ let {yield = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with const.
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ const {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ const {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ const {yield = 0} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ const {a: yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ const {yield} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ const {yield = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns in parameters.
+assertThrowsInstanceOf(() => eval(`
+ function* g({a: yield} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g({yield} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g({yield = 0} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g({a: yield} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g({yield} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g({yield = 0} = {}) { }
+`), SyntaxError);
+
+
+// Destructuring assignment pattern.
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ ({a: yield} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ ({yield} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ function* g() {
+ ({yield = 0} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ ({a: yield} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ ({yield} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ function* g() {
+ ({yield = 0} = {});
+ }
+`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/destructuring/yield-in-object-destr-script.js b/js/src/tests/non262/destructuring/yield-in-object-destr-script.js
new file mode 100644
index 0000000000..99b48dd417
--- /dev/null
+++ b/js/src/tests/non262/destructuring/yield-in-object-destr-script.js
@@ -0,0 +1,123 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring binding patterns with var.
+var {a: yield} = {a: "yield-with-name"};
+assertEq(yield, "yield-with-name");
+
+var {yield} = {yield: "yield-with-shorthand"};
+assertEq(yield, "yield-with-shorthand");
+
+var {yield = 0} = {yield: "yield-with-coverinitname"};
+assertEq(yield, "yield-with-coverinitname");
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ var {a: yield} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ var {yield} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ var {yield = 0} = {};
+`), SyntaxError);
+
+
+// Destructuring binding patterns with let.
+{
+ let {a: yield} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+}
+
+{
+ let {yield} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+}
+
+{
+ let {yield = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+}
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ let {a: yield} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ let {yield} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ let {yield = 0} = {};
+`), SyntaxError);
+
+
+// Destructuring binding patterns with const.
+{
+ const {a: yield} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+}
+
+{
+ const {yield} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+}
+
+{
+ const {yield = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+}
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ const {a: yield} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ const {yield} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ const {yield = 0} = {};
+`), SyntaxError);
+
+
+// Destructuring assignment pattern.
+({a: yield} = {a: "yield-with-name"});
+assertEq(yield, "yield-with-name");
+
+({yield} = {yield: "yield-with-shorthand"});
+assertEq(yield, "yield-with-shorthand");
+
+({yield = 0} = {yield: "yield-with-coverinitname"});
+assertEq(yield, "yield-with-coverinitname");
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ ({a: yield} = {});
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ ({yield} = {});
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ "use strict";
+ ({yield = 0} = {});
+`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-function.js b/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-function.js
new file mode 100644
index 0000000000..349badeaf7
--- /dev/null
+++ b/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-function.js
@@ -0,0 +1,182 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring binding patterns with var.
+(function() {
+ var {a: yi\u0065ld} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+
+ var {yi\u0065ld} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+
+ var {yi\u0065ld = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ var {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ var {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ var {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with let.
+(function(){
+ let {a: yi\u0065ld} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+})();
+
+(function() {
+ let {yi\u0065ld} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+})();
+
+(function() {
+ let {yi\u0065ld = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ let {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ let {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ let {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with const.
+(function() {
+ const {a: yi\u0065ld} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+})();
+
+(function() {
+ const {yi\u0065ld} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+})();
+
+(function() {
+ const {yi\u0065ld = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ const {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ const {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ const {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns in parameters.
+(function({a: yi\u0065ld} = {a: "yield-with-name"}) {
+ assertEq(yield, "yield-with-name");
+})();
+
+(function({yi\u0065ld} = {yield: "yield-with-shorthand"}) {
+ assertEq(yield, "yield-with-shorthand");
+})();
+
+(function({yi\u0065ld = 0} = {yield: "yield-with-coverinitname"}) {
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f({a: yi\u0065ld} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f({yi\u0065ld} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f({yi\u0065ld = 0} = {}) { }
+`), SyntaxError);
+
+
+// Destructuring assignment pattern.
+(function() {
+ var a, yield;
+
+ ({a: yi\u0065ld} = {a: "yield-with-name"});
+ assertEq(yield, "yield-with-name");
+
+ ({yi\u0065ld} = {yield: "yield-with-shorthand"});
+ assertEq(yield, "yield-with-shorthand");
+
+ ({yi\u0065ld = 0} = {yield: "yield-with-coverinitname"});
+ assertEq(yield, "yield-with-coverinitname");
+})();
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ ({a: yi\u0065ld} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ ({yi\u0065ld} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function f() {
+ ({yi\u0065ld = 0} = {});
+ }
+`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-generator.js b/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-generator.js
new file mode 100644
index 0000000000..faa3563914
--- /dev/null
+++ b/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-generator.js
@@ -0,0 +1,200 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring binding patterns with var.
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ var {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ var {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ var {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ var {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ var {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ var {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with let.
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ let {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ let {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ let {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ let {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ let {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ let {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns with const.
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ const {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ const {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ const {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ const {a: yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ const {yi\u0065ld} = {};
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ const {yi\u0065ld = 0} = {};
+ }
+`), SyntaxError);
+
+
+// Destructuring binding patterns in parameters.
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g({a: yi\u0065ld} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g({yi\u0065ld} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g({yi\u0065ld = 0} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g({a: yi\u0065ld} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g({yi\u0065ld} = {}) { }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g({yi\u0065ld = 0} = {}) { }
+`), SyntaxError);
+
+
+// Destructuring assignment pattern.
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ ({a: yi\u0065ld} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ ({yi\u0065ld} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ function* g() {
+ ({yi\u0065ld = 0} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ ({a: yi\u0065ld} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ ({yi\u0065ld} = {});
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ function* g() {
+ ({yi\u0065ld = 0} = {});
+ }
+`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-script.js b/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-script.js
new file mode 100644
index 0000000000..65352a66cf
--- /dev/null
+++ b/js/src/tests/non262/destructuring/yield-with-escape-in-object-destr-script.js
@@ -0,0 +1,123 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Destructuring binding patterns with var.
+var {a: yi\u0065ld} = {a: "yield-with-name"};
+assertEq(yield, "yield-with-name");
+
+var {yi\u0065ld} = {yield: "yield-with-shorthand"};
+assertEq(yield, "yield-with-shorthand");
+
+var {yi\u0065ld = 0} = {yield: "yield-with-coverinitname"};
+assertEq(yield, "yield-with-coverinitname");
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ var {a: yi\u0065ld} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ var {yi\u0065ld} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ var {yi\u0065ld = 0} = {};
+`), SyntaxError);
+
+
+// Destructuring binding patterns with let.
+{
+ let {a: yi\u0065ld} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+}
+
+{
+ let {yi\u0065ld} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+}
+
+{
+ let {yi\u0065ld = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+}
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ let {a: yi\u0065ld} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ let {yi\u0065ld} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ let {yi\u0065ld = 0} = {};
+`), SyntaxError);
+
+
+// Destructuring binding patterns with const.
+{
+ const {a: yi\u0065ld} = {a: "yield-with-name"};
+ assertEq(yield, "yield-with-name");
+}
+
+{
+ const {yi\u0065ld} = {yield: "yield-with-shorthand"};
+ assertEq(yield, "yield-with-shorthand");
+}
+
+{
+ const {yi\u0065ld = 0} = {yield: "yield-with-coverinitname"};
+ assertEq(yield, "yield-with-coverinitname");
+}
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ const {a: yi\u0065ld} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ const {yi\u0065ld} = {};
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ const {yi\u0065ld = 0} = {};
+`), SyntaxError);
+
+
+// Destructuring assignment pattern.
+({a: yi\u0065ld} = {a: "yield-with-name"});
+assertEq(yield, "yield-with-name");
+
+({yi\u0065ld} = {yield: "yield-with-shorthand"});
+assertEq(yield, "yield-with-shorthand");
+
+({yi\u0065ld = 0} = {yield: "yield-with-coverinitname"});
+assertEq(yield, "yield-with-coverinitname");
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ ({a: yi\u0065ld} = {});
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ ({yi\u0065ld} = {});
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ "use strict";
+ ({yi\u0065ld = 0} = {});
+`), SyntaxError);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");