summaryrefslogtreecommitdiff
path: root/js/src/tests/ecma_6
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/ecma_6')
-rw-r--r--js/src/tests/ecma_6/Array/from-iterator-close.js183
-rw-r--r--js/src/tests/ecma_6/Class/className.js20
-rw-r--r--js/src/tests/ecma_6/Destructuring/array-default-class.js25
-rw-r--r--js/src/tests/ecma_6/Destructuring/array-iterator-close.js93
-rw-r--r--js/src/tests/ecma_6/Destructuring/order-super.js727
-rw-r--r--js/src/tests/ecma_6/Destructuring/order.js745
-rw-r--r--js/src/tests/ecma_6/Error/constructor-proto.js17
-rw-r--r--js/src/tests/ecma_6/Error/prototype-properties.js24
-rw-r--r--js/src/tests/ecma_6/Error/prototype.js18
-rw-r--r--js/src/tests/ecma_6/Error/shell.js0
-rw-r--r--js/src/tests/ecma_6/Function/function-name-assignment.js139
-rw-r--r--js/src/tests/ecma_6/Function/function-name-binding.js54
-rw-r--r--js/src/tests/ecma_6/Function/function-name-class.js32
-rw-r--r--js/src/tests/ecma_6/Function/function-name-for.js31
-rw-r--r--js/src/tests/ecma_6/Function/function-name-method.js70
-rw-r--r--js/src/tests/ecma_6/Function/function-name-property.js58
-rw-r--r--js/src/tests/ecma_6/Function/invalid-parameter-list.js27
-rw-r--r--js/src/tests/ecma_6/Generators/construct-newtarget.js79
-rw-r--r--js/src/tests/ecma_6/Generators/delegating-yield-2.js20
-rw-r--r--js/src/tests/ecma_6/Generators/subclass.js33
-rw-r--r--js/src/tests/ecma_6/Generators/yield-iterator-close.js58
-rw-r--r--js/src/tests/ecma_6/Generators/yield-star-iterator-close.js153
-rw-r--r--js/src/tests/ecma_6/Map/constructor-iterator-close.js253
-rw-r--r--js/src/tests/ecma_6/Object/accessor-name.js9
-rw-r--r--js/src/tests/ecma_6/Promise/iterator-close.js234
-rw-r--r--js/src/tests/ecma_6/RegExp/compile-lastIndex.js34
-rw-r--r--js/src/tests/ecma_6/RegExp/compile-symbol.js14
-rw-r--r--js/src/tests/ecma_6/RegExp/constructor-symbol.js14
-rw-r--r--js/src/tests/ecma_6/RegExp/match-local-tolength-recompilation.js75
-rw-r--r--js/src/tests/ecma_6/RegExp/prototype.js31
-rw-r--r--js/src/tests/ecma_6/RegExp/replace-local-tolength-lastindex.js22
-rw-r--r--js/src/tests/ecma_6/RegExp/replace-local-tolength-recompilation.js75
-rw-r--r--js/src/tests/ecma_6/RegExp/search-trace.js2
-rw-r--r--js/src/tests/ecma_6/Statements/for-inof-finally.js78
-rw-r--r--js/src/tests/ecma_6/Statements/for-of-iterator-close-throw.js35
-rw-r--r--js/src/tests/ecma_6/Statements/for-of-iterator-close.js102
-rw-r--r--js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js18
-rw-r--r--js/src/tests/ecma_6/shell.js52
38 files changed, 3580 insertions, 74 deletions
diff --git a/js/src/tests/ecma_6/Array/from-iterator-close.js b/js/src/tests/ecma_6/Array/from-iterator-close.js
new file mode 100644
index 0000000000..fa97ea282a
--- /dev/null
+++ b/js/src/tests/ecma_6/Array/from-iterator-close.js
@@ -0,0 +1,183 @@
+var BUGNUMBER = 1180306;
+var summary = 'Array.from should close iterator on error';
+
+print(BUGNUMBER + ": " + summary);
+
+function test(ctor, { mapVal=undefined,
+ nextVal=undefined,
+ nextThrowVal=undefined,
+ modifier=undefined,
+ exceptionVal=undefined,
+ exceptionType=undefined,
+ closed=true }) {
+ let iterable = {
+ closed: false,
+ [Symbol.iterator]() {
+ let iterator = {
+ first: true,
+ next() {
+ if (this.first) {
+ this.first = false;
+ if (nextThrowVal)
+ throw nextThrowVal;
+ return nextVal;
+ }
+ return { value: undefined, done: true };
+ },
+ return() {
+ iterable.closed = true;
+ return {};
+ }
+ };
+ if (modifier)
+ modifier(iterator, iterable);
+
+ return iterator;
+ }
+ };
+ if (exceptionVal) {
+ let caught = false;
+ try {
+ ctor.from(iterable, mapVal);
+ } catch (e) {
+ assertEq(e, exceptionVal);
+ caught = true;
+ }
+ assertEq(caught, true);
+ } else if (exceptionType) {
+ assertThrowsInstanceOf(() => ctor.from(iterable, mapVal), exceptionType);
+ } else {
+ ctor.from(iterable, mapVal);
+ }
+ assertEq(iterable.closed, closed);
+}
+
+// == Error cases with close ==
+
+// ES 2017 draft 22.1.2.1 step 5.e.i.1.
+// Cannot test.
+
+// ES 2017 draft 22.1.2.1 step 5.e.vi.2.
+test(Array, {
+ mapVal: () => { throw "map throws"; },
+ nextVal: { value: 1, done: false },
+ exceptionVal: "map throws",
+ closed: true,
+});
+
+// ES 2017 draft 22.1.2.1 step 5.e.ix.
+class MyArray extends Array {
+ constructor() {
+ return new Proxy({}, {
+ defineProperty() {
+ throw "defineProperty throws";
+ }
+ });
+ }
+}
+test(MyArray, {
+ nextVal: { value: 1, done: false },
+ exceptionVal: "defineProperty throws",
+ closed: true,
+});
+
+// ES 2017 draft 7.4.6 step 3.
+// if GetMethod fails, the thrown value should be used.
+test(MyArray, {
+ nextVal: { value: 1, done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ throw "return getter throws";
+ }
+ });
+ },
+ exceptionVal: "return getter throws",
+ closed: true,
+});
+test(MyArray, {
+ nextVal: { value: 1, done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ return "non object";
+ }
+ });
+ },
+ exceptionType: TypeError,
+ closed: true,
+});
+test(MyArray, {
+ nextVal: { value: 1, done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ // Non callable.
+ return {};
+ }
+ });
+ },
+ exceptionType: TypeError,
+ closed: true,
+});
+
+// ES 2017 draft 7.4.6 steps 6.
+// if return method throws, the thrown value should be ignored.
+test(MyArray, {
+ nextVal: { value: 1, done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ throw "return throws";
+ };
+ },
+ exceptionVal: "defineProperty throws",
+ closed: true,
+});
+
+test(MyArray, {
+ nextVal: { value: 1, done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ return "non object";
+ };
+ },
+ exceptionVal: "defineProperty throws",
+ closed: true,
+});
+
+// == Error cases without close ==
+
+// ES 2017 draft 22.1.2.1 step 5.e.iii.
+test(Array, {
+ nextThrowVal: "next throws",
+ exceptionVal: "next throws",
+ closed: false,
+});
+
+test(Array, {
+ nextVal: { value: {}, get done() { throw "done getter throws"; } },
+ exceptionVal: "done getter throws",
+ closed: false,
+});
+
+// ES 2017 draft 22.1.2.1 step 5.e.v.
+test(Array, {
+ nextVal: { get value() { throw "value getter throws"; }, done: false },
+ exceptionVal: "value getter throws",
+ closed: false,
+});
+
+// == Successful cases ==
+
+test(Array, {
+ nextVal: { value: 1, done: false },
+ closed: false,
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/Class/className.js b/js/src/tests/ecma_6/Class/className.js
index a33397a8a3..ad3920c151 100644
--- a/js/src/tests/ecma_6/Class/className.js
+++ b/js/src/tests/ecma_6/Class/className.js
@@ -174,27 +174,29 @@ testName(ExtendedExpr3, "base", false, false, false);
// Anonymous class expressions don't get name properties unless specified in a
// static manner.
-let Anon = class {
+// Use property assignment to avoid setting name property.
+let tmp = {};
+let Anon = tmp.value = class {
constructor() {}
};
testName(Anon, "", false, false, false);
-let AnonDefault = class { };
+let AnonDefault = tmp.value = class { };
testName(AnonDefault, "", false, false, false);
-let AnonWithGetter = class {
+let AnonWithGetter = tmp.value = class {
constructor() {}
static get name() { return "base"; }
};
testName(AnonWithGetter, "base", false, true, false);
-let AnonWithSetter = class {
+let AnonWithSetter = tmp.value = class {
constructor() {}
static set name(v) {}
};
testName(AnonWithSetter, undefined, false, false, true);
-let AnonWithGetterSetter = class {
+let AnonWithGetterSetter = tmp.value = class {
constructor() {}
static get name() { return "base"; }
static set name(v) {}
@@ -202,15 +204,15 @@ let AnonWithGetterSetter = class {
testName(AnonWithGetterSetter, "base", false, true, true);
-let ExtendedAnon1 = class extends Anon {
+let ExtendedAnon1 = tmp.value = class extends Anon {
constructor() {}
};
testName(ExtendedAnon1, "", false, false, false);
-let ExtendedAnonDefault = class extends Anon { };
+let ExtendedAnonDefault = tmp.value = class extends Anon { };
testName(ExtendedAnonDefault, "", false, false, false);
-let ExtendedAnon2 = class extends AnonWithGetterSetter {
+let ExtendedAnon2 = tmp.value = class extends AnonWithGetterSetter {
constructor() {}
static get name() { return "extend"; }
};
@@ -218,7 +220,7 @@ testName(ExtendedAnon2, "extend", false, true, false);
delete ExtendedAnon2.name;
testName(ExtendedAnon2, "base", false, false, false);
-let ExtendedAnon3 = class extends AnonWithGetterSetter {
+let ExtendedAnon3 = tmp.value = class extends AnonWithGetterSetter {
constructor() {}
static set name(v) {}
};
diff --git a/js/src/tests/ecma_6/Destructuring/array-default-class.js b/js/src/tests/ecma_6/Destructuring/array-default-class.js
new file mode 100644
index 0000000000..5aa9c579b1
--- /dev/null
+++ b/js/src/tests/ecma_6/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/ecma_6/Destructuring/array-iterator-close.js b/js/src/tests/ecma_6/Destructuring/array-iterator-close.js
new file mode 100644
index 0000000000..ed35135dba
--- /dev/null
+++ b/js/src/tests/ecma_6/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/ecma_6/Destructuring/order-super.js b/js/src/tests/ecma_6/Destructuring/order-super.js
new file mode 100644
index 0000000000..afe11e2d91
--- /dev/null
+++ b/js/src/tests/ecma_6/Destructuring/order-super.js
@@ -0,0 +1,727 @@
+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",
+
+ "lhs before name a",
+ "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");
+
+ // 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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before name a",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set b",
+
+ "lhs before name c",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before name a",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before name b",
+ "rhs get a::@@iterator()::next",
+ "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",
+
+ "lhs before name a",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+
+ "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",
+
+ "lhs before name b",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "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",
+
+ "lhs before name g",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
+ "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 get @@iterator()::next",
+ "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",
+
+ "lhs before name j",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next",
+ "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 get @@iterator()::next()::value::i::@@iterator()::next",
+ "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",
+
+ "lhs before name l",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before name n",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "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",
+
+ "lhs before name s",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
+ "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",
+
+ "lhs before name u",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "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",
+
+ "lhs before name z",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
+ "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/ecma_6/Destructuring/order.js b/js/src/tests/ecma_6/Destructuring/order.js
new file mode 100644
index 0000000000..4eb48cd2b0
--- /dev/null
+++ b/js/src/tests/ecma_6/Destructuring/order.js
@@ -0,0 +1,745 @@
+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",
+
+ "lhs before obj a",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj a",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj a",
+ "rhs get @@iterator()::next",
+ "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 get @@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "rhs call @@iterator()::next()::value::@@iterator()::next",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs get a::@@iterator()::next",
+ "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",
+
+ "lhs before obj a",
+ "lhs before name a",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "lhs set a",
+
+ "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",
+
+ "lhs before obj b",
+ "lhs before name b",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "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",
+
+ "lhs before obj g",
+ "lhs before name g",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
+ "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 get @@iterator()::next",
+ "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",
+
+ "lhs before obj j",
+ "lhs before name j",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next",
+ "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 get @@iterator()::next()::value::i::@@iterator()::next",
+ "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",
+
+ "lhs before obj l",
+ "lhs before name l",
+ "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
+ "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 get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "rhs call @@iterator()::next",
+ "rhs get @@iterator()::next()::done",
+ "rhs get @@iterator()::next()::value",
+ "rhs get @@iterator()::next",
+ "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",
+
+ "lhs before obj n",
+ "lhs before name n",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "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",
+
+ "lhs before obj s",
+ "lhs before name s",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
+ "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",
+
+ "lhs before obj u",
+ "lhs before name u",
+ "rhs get @@iterator()::next()::value::@@iterator()::next",
+ "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 get @@iterator()::next()::value::@@iterator()::next",
+ "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",
+
+ "lhs before obj z",
+ "lhs before name z",
+ "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
+ "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/ecma_6/Error/constructor-proto.js b/js/src/tests/ecma_6/Error/constructor-proto.js
new file mode 100644
index 0000000000..4ddc6025e8
--- /dev/null
+++ b/js/src/tests/ecma_6/Error/constructor-proto.js
@@ -0,0 +1,17 @@
+const nativeErrors = [
+ InternalError,
+ EvalError,
+ RangeError,
+ ReferenceError,
+ SyntaxError,
+ TypeError,
+ URIError
+];
+
+assertEq(Reflect.getPrototypeOf(Error), Function.prototype)
+
+for (const error of nativeErrors)
+ assertEq(Reflect.getPrototypeOf(error), Error);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Error/prototype-properties.js b/js/src/tests/ecma_6/Error/prototype-properties.js
new file mode 100644
index 0000000000..c66caf2bcb
--- /dev/null
+++ b/js/src/tests/ecma_6/Error/prototype-properties.js
@@ -0,0 +1,24 @@
+const nativeErrors = [
+ InternalError,
+ EvalError,
+ RangeError,
+ ReferenceError,
+ SyntaxError,
+ TypeError,
+ URIError
+];
+
+
+assertEq(Reflect.ownKeys(Error.prototype).toString(), "toSource,toString,message,name,stack,constructor");
+assertEq(Error.prototype.name, "Error");
+assertEq(Error.prototype.message, "");
+
+for (const error of nativeErrors) {
+ assertEq(Reflect.ownKeys(error.prototype).toString(), "message,name,constructor");
+ assertEq(error.prototype.name, error.name);
+ assertEq(error.prototype.message, "");
+ assertEq(error.prototype.constructor, error);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Error/prototype.js b/js/src/tests/ecma_6/Error/prototype.js
new file mode 100644
index 0000000000..b22a8e084b
--- /dev/null
+++ b/js/src/tests/ecma_6/Error/prototype.js
@@ -0,0 +1,18 @@
+const nativeErrors = [
+ InternalError,
+ EvalError,
+ RangeError,
+ ReferenceError,
+ SyntaxError,
+ TypeError,
+ URIError
+];
+
+assertEq(Reflect.getPrototypeOf(Error.prototype), Object.prototype)
+
+for (const error of nativeErrors) {
+ assertEq(Reflect.getPrototypeOf(error.prototype), Error.prototype);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Error/shell.js b/js/src/tests/ecma_6/Error/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/ecma_6/Error/shell.js
diff --git a/js/src/tests/ecma_6/Function/function-name-assignment.js b/js/src/tests/ecma_6/Function/function-name-assignment.js
new file mode 100644
index 0000000000..5e4d1c004f
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/function-name-assignment.js
@@ -0,0 +1,139 @@
+var BUGNUMBER = 883377;
+var summary = "Anonymous function name should be set based on assignment";
+
+print(BUGNUMBER + ": " + summary);
+
+var fooSymbol = Symbol("foo");
+var emptySymbol = Symbol("");
+var undefSymbol = Symbol();
+var globalVar;
+
+var exprs = [
+ ["function() {}", false],
+ ["function named() {}", true],
+ ["function*() {}", false],
+ ["function* named() {}", true],
+ ["async function() {}", false],
+ ["async function named() {}", true],
+ ["() => {}", false],
+ ["async () => {}", false],
+ ["class {}", false],
+ ["class named {}", true],
+];
+
+function testAssignmentExpression(expr, named) {
+ eval(`
+ var assignment;
+ assignment = ${expr};
+ assertEq(assignment.name, named ? "named" : "assignment");
+
+ globalVar = ${expr};
+ assertEq(globalVar.name, named ? "named" : "globalVar");
+
+ var obj = { dynamic: null };
+ with (obj) {
+ dynamic = ${expr};
+ }
+ assertEq(obj.dynamic.name, named ? "named" : "dynamic");
+
+ (function namedLambda(param1, param2) {
+ var assignedToNamedLambda;
+ assignedToNamedLambda = namedLambda = ${expr};
+ assertEq(namedLambda.name, "namedLambda");
+ assertEq(assignedToNamedLambda.name, named ? "named" : "namedLambda");
+
+ param1 = ${expr};
+ assertEq(param1.name, named ? "named" : "param1");
+
+ {
+ let param1 = ${expr};
+ assertEq(param1.name, named ? "named" : "param1");
+
+ param2 = ${expr};
+ assertEq(param2.name, named ? "named" : "param2");
+ }
+ })();
+
+ {
+ let nextedLexical1, nextedLexical2;
+ {
+ let nextedLexical1 = ${expr};
+ assertEq(nextedLexical1.name, named ? "named" : "nextedLexical1");
+
+ nextedLexical2 = ${expr};
+ assertEq(nextedLexical2.name, named ? "named" : "nextedLexical2");
+ }
+ }
+ `);
+
+ // Not applicable cases: not IsIdentifierRef.
+ eval(`
+ var inParen;
+ (inParen) = ${expr};
+ assertEq(inParen.name, named ? "named" : "");
+ `);
+
+ // Not applicable cases: not direct RHS.
+ if (!expr.includes("=>")) {
+ eval(`
+ var a = true && ${expr};
+ assertEq(a.name, named ? "named" : "");
+ `);
+ } else {
+ // Arrow function cannot be RHS of &&.
+ eval(`
+ var a = true && (${expr});
+ assertEq(a.name, named ? "named" : "");
+ `);
+ }
+
+ // Not applicable cases: property.
+ eval(`
+ var obj = {};
+
+ obj.prop = ${expr};
+ assertEq(obj.prop.name, named ? "named" : "");
+
+ obj["literal"] = ${expr};
+ assertEq(obj["literal"].name, named ? "named" : "");
+ `);
+
+ // Not applicable cases: assigned again.
+ eval(`
+ var tmp = [${expr}];
+ assertEq(tmp[0].name, named ? "named" : "");
+
+ var assignment;
+ assignment = tmp[0];
+ assertEq(assignment.name, named ? "named" : "");
+ `);
+}
+for (var [expr, named] of exprs) {
+ testAssignmentExpression(expr, named);
+}
+
+function testVariableDeclaration(expr, named) {
+ eval(`
+ var varDecl = ${expr};
+ assertEq(varDecl.name, named ? "named" : "varDecl");
+ `);
+}
+for (var [expr, named] of exprs) {
+ testVariableDeclaration(expr, named);
+}
+
+function testLexicalBinding(expr, named) {
+ eval(`
+ let lexical = ${expr};
+ assertEq(lexical.name, named ? "named" : "lexical");
+
+ const constLexical = ${expr};
+ assertEq(constLexical.name, named ? "named" : "constLexical");
+ `);
+}
+for (var [expr, named] of exprs) {
+ testLexicalBinding(expr, named);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Function/function-name-binding.js b/js/src/tests/ecma_6/Function/function-name-binding.js
new file mode 100644
index 0000000000..bdd6c131c0
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/function-name-binding.js
@@ -0,0 +1,54 @@
+var BUGNUMBER = 883377;
+var summary = "Anonymous function name should be set based on binding pattern";
+
+print(BUGNUMBER + ": " + summary);
+
+var exprs = [
+ ["function() {}", false],
+ ["function named() {}", true],
+ ["function*() {}", false],
+ ["function* named() {}", true],
+ ["async function() {}", false],
+ ["async function named() {}", true],
+ ["() => {}", false],
+ ["async () => {}", false],
+ ["class {}", false],
+ ["class named {}", true],
+];
+
+function testAssignmentProperty(expr, named) {
+ var f = eval(`(function({ prop1 = ${expr} }) { return prop1; })`);
+ assertEq(f({}).name, named ? "named" : "prop1");
+
+ eval(`
+ var { prop1 = ${expr} } = {};
+ assertEq(prop1.name, named ? "named" : "prop1");
+ `);
+}
+for (var [expr, named] of exprs) {
+ testAssignmentProperty(expr, named);
+}
+
+function testAssignmentElement(expr, named) {
+ var f = eval(`(function([elem1 = ${expr}]) { return elem1; })`);
+ assertEq(f([]).name, named ? "named" : "elem1");
+
+ eval(`
+ var [elem1 = ${expr}] = [];
+ assertEq(elem1.name, named ? "named" : "elem1");
+ `);
+}
+for (var [expr, named] of exprs) {
+ testAssignmentElement(expr, named);
+}
+
+function testSingleNameBinding(expr, named) {
+ var f = eval(`(function(param1 = ${expr}) { return param1; })`);
+ assertEq(f().name, named ? "named" : "param1");
+}
+for (var [expr, named] of exprs) {
+ testSingleNameBinding(expr, named);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Function/function-name-class.js b/js/src/tests/ecma_6/Function/function-name-class.js
new file mode 100644
index 0000000000..edde690556
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/function-name-class.js
@@ -0,0 +1,32 @@
+var BUGNUMBER = 883377;
+var summary = "Anonymous class with name method shouldn't be affected by assignment";
+
+print(BUGNUMBER + ": " + summary);
+
+var classWithStaticNameMethod = class { static name() {} };
+assertEq(typeof classWithStaticNameMethod.name, "function");
+
+var classWithStaticNameGetter = class { static get name() { return "static name"; } };
+assertEq(typeof Object.getOwnPropertyDescriptor(classWithStaticNameGetter, "name").get, "function");
+assertEq(classWithStaticNameGetter.name, "static name");
+
+var classWithStaticNameSetter = class { static set name(v) {} };
+assertEq(typeof Object.getOwnPropertyDescriptor(classWithStaticNameSetter, "name").set, "function");
+
+var n = "NAME".toLowerCase();
+var classWithStaticNameMethodComputed = class { static [n]() {} };
+assertEq(typeof classWithStaticNameMethodComputed.name, "function");
+
+// It doesn't apply for non-static method.
+
+var classWithNameMethod = class { name() {} };
+assertEq(classWithNameMethod.name, "classWithNameMethod");
+
+var classWithNameGetter = class { get name() { return "name"; } };
+assertEq(classWithNameGetter.name, "classWithNameGetter");
+
+var classWithNameSetter = class { set name(v) {} };
+assertEq(classWithNameSetter.name, "classWithNameSetter");
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Function/function-name-for.js b/js/src/tests/ecma_6/Function/function-name-for.js
new file mode 100644
index 0000000000..2f04a5fa8d
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/function-name-for.js
@@ -0,0 +1,31 @@
+var BUGNUMBER = 883377;
+var summary = "Anonymous function name should be set based on for-in initializer";
+
+print(BUGNUMBER + ": " + summary);
+
+var exprs = [
+ ["function() {}", false],
+ ["function named() {}", true],
+ ["function*() {}", false],
+ ["function* named() {}", true],
+ ["async function() {}", false],
+ ["async function named() {}", true],
+ ["() => {}", false],
+ ["async () => {}", false],
+ ["class {}", false],
+ ["class named {}", true],
+];
+
+function testForInHead(expr, named) {
+ eval(`
+ for (var forInHead = ${expr} in {}) {
+ }
+ `);
+ assertEq(forInHead.name, named ? "named" : "forInHead");
+}
+for (var [expr, named] of exprs) {
+ testForInHead(expr, named);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Function/function-name-method.js b/js/src/tests/ecma_6/Function/function-name-method.js
new file mode 100644
index 0000000000..3b2eeee793
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/function-name-method.js
@@ -0,0 +1,70 @@
+var BUGNUMBER = 883377;
+var summary = "Anonymous function name should be set based on method definition";
+
+print(BUGNUMBER + ": " + summary);
+
+var fooSymbol = Symbol("foo");
+var emptySymbol = Symbol("");
+var undefSymbol = Symbol();
+
+function testMethod(prefix, classPrefix="", prototype=false) {
+ var param = (prefix == "set" || prefix == "static set") ? "v" : "";
+ var sep = classPrefix ? "" : ",";
+ var objOrClass = eval(`(${classPrefix}{
+ ${prefix} prop(${param}) {} ${sep}
+ ${prefix} "literal"(${param}) {} ${sep}
+ ${prefix} ""(${param}) {} ${sep}
+ ${prefix} 5(${param}) {} ${sep}
+ ${prefix} [Symbol.iterator](${param}) {} ${sep}
+ ${prefix} [fooSymbol](${param}) {} ${sep}
+ ${prefix} [emptySymbol](${param}) {} ${sep}
+ ${prefix} [undefSymbol](${param}) {} ${sep}
+ ${prefix} [/a/](${param}) {} ${sep}
+ })`);
+
+ var target = prototype ? objOrClass.prototype : objOrClass;
+
+ function testOne(methodName, expectedName) {
+ var f;
+ if (prefix == "get" || prefix == "static get") {
+ f = Object.getOwnPropertyDescriptor(target, methodName).get;
+ expectedName = "get " + expectedName;
+ } else if (prefix == "set" || prefix == "static set") {
+ f = Object.getOwnPropertyDescriptor(target, methodName).set;
+ expectedName = "set " + expectedName;
+ } else {
+ f = Object.getOwnPropertyDescriptor(target, methodName).value;
+ }
+
+ assertEq(f.name, expectedName);
+ }
+ testOne("prop", "prop");
+ testOne("literal", "literal");
+ testOne("", "");
+ testOne(5, "5");
+ testOne(Symbol.iterator, "[Symbol.iterator]");
+ testOne(fooSymbol, "[foo]");
+ testOne(emptySymbol, "[]");
+ testOne(undefSymbol, "");
+ testOne(/a/, "/a/");
+}
+testMethod("");
+testMethod("*");
+testMethod("async");
+testMethod("get");
+testMethod("set");
+
+testMethod("", "class", true);
+testMethod("*", "class", true);
+testMethod("async", "class", true);
+testMethod("get", "class", true);
+testMethod("set", "class", true);
+
+testMethod("static", "class");
+testMethod("static *", "class");
+testMethod("static async", "class");
+testMethod("static get", "class");
+testMethod("static set", "class");
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Function/function-name-property.js b/js/src/tests/ecma_6/Function/function-name-property.js
new file mode 100644
index 0000000000..7ad174b10f
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/function-name-property.js
@@ -0,0 +1,58 @@
+var BUGNUMBER = 883377;
+var summary = "Anonymous function name should be set based on property name";
+
+print(BUGNUMBER + ": " + summary);
+
+var fooSymbol = Symbol("foo");
+var emptySymbol = Symbol("");
+var undefSymbol = Symbol();
+
+var exprs = [
+ ["function() {}", false],
+ ["function named() {}", true],
+ ["function*() {}", false],
+ ["function* named() {}", true],
+ ["async function() {}", false],
+ ["async function named() {}", true],
+ ["() => {}", false],
+ ["async () => {}", false],
+ ["class {}", false],
+ ["class named {}", true],
+];
+
+function testPropertyDefinition(expr, named) {
+ var obj = eval(`({
+ prop: ${expr},
+ "literal": ${expr},
+ "": ${expr},
+ 5: ${expr},
+ 0.4: ${expr},
+ [Symbol.iterator]: ${expr},
+ [fooSymbol]: ${expr},
+ [emptySymbol]: ${expr},
+ [undefSymbol]: ${expr},
+ [/a/]: ${expr},
+ })`);
+ assertEq(obj.prop.name, named ? "named" : "prop");
+ assertEq(obj["literal"].name, named ? "named" : "literal");
+ assertEq(obj[""].name, named ? "named" : "");
+ assertEq(obj[5].name, named ? "named" : "5");
+ assertEq(obj[0.4].name, named ? "named" : "0.4");
+ assertEq(obj[Symbol.iterator].name, named ? "named" : "[Symbol.iterator]");
+ assertEq(obj[fooSymbol].name, named ? "named" : "[foo]");
+ assertEq(obj[emptySymbol].name, named ? "named" : "[]");
+ assertEq(obj[undefSymbol].name, named ? "named" : "");
+ assertEq(obj[/a/].name, named ? "named" : "/a/");
+
+ // Not applicable cases: __proto__.
+ obj = {
+ __proto__: function() {}
+ };
+ assertEq(obj.__proto__.name, "");
+}
+for (var [expr, named] of exprs) {
+ testPropertyDefinition(expr, named);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Function/invalid-parameter-list.js b/js/src/tests/ecma_6/Function/invalid-parameter-list.js
new file mode 100644
index 0000000000..8aae89ef15
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/invalid-parameter-list.js
@@ -0,0 +1,27 @@
+// This constructor behaves like `Function` without checking
+// if the parameter list end is at the expected position.
+// We use this to make sure that the tests we use are otherwise
+// syntactically correct.
+function DumpFunction(...args) {
+ let code = "function anonymous(";
+ code += args.slice(0, -1).join(", ");
+ code += ") {\n";
+ code += args[args.length -1];
+ code += "\n}";
+ eval(code);
+}
+
+const tests = [
+ ["/*", "*/) {"],
+ ["//", ") {"],
+ ["a = `", "` ) {"],
+ [") { var x = function (", "} "],
+ ["x = function (", "}) {"]
+];
+
+for (const test of tests) {
+ DumpFunction(...test);
+ assertThrowsInstanceOf(() => new Function(...test), SyntaxError);
+}
+
+reportCompare(0, 0, 'ok');
diff --git a/js/src/tests/ecma_6/Generators/construct-newtarget.js b/js/src/tests/ecma_6/Generators/construct-newtarget.js
new file mode 100644
index 0000000000..f2087852b0
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/construct-newtarget.js
@@ -0,0 +1,79 @@
+/* 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 GeneratorFunction = function*(){}.constructor;
+
+
+// Test subclassing %GeneratorFunction% works correctly.
+class MyGenerator extends GeneratorFunction {}
+
+var fn = new MyGenerator();
+assertEq(fn instanceof MyGenerator, true);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
+
+fn = Reflect.construct(MyGenerator, []);
+assertEq(fn instanceof MyGenerator, true);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
+
+fn = Reflect.construct(MyGenerator, [], MyGenerator);
+assertEq(fn instanceof MyGenerator, true);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
+
+fn = Reflect.construct(MyGenerator, [], GeneratorFunction);
+assertEq(fn instanceof MyGenerator, false);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+
+// Set a different constructor as NewTarget.
+fn = Reflect.construct(MyGenerator, [], Array);
+assertEq(fn instanceof MyGenerator, false);
+assertEq(fn instanceof GeneratorFunction, false);
+assertEq(Object.getPrototypeOf(fn), Array.prototype);
+
+fn = Reflect.construct(GeneratorFunction, [], Array);
+assertEq(fn instanceof GeneratorFunction, false);
+assertEq(Object.getPrototypeOf(fn), Array.prototype);
+
+
+// The prototype defaults to %GeneratorFunctionPrototype% if null.
+function NewTargetNullPrototype() {}
+NewTargetNullPrototype.prototype = null;
+
+fn = Reflect.construct(GeneratorFunction, [], NewTargetNullPrototype);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+fn = Reflect.construct(MyGenerator, [], NewTargetNullPrototype);
+assertEq(fn instanceof MyGenerator, false);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+
+// "prototype" property is retrieved exactly once.
+var trapLog = [], getLog = [];
+var ProxiedConstructor = new Proxy(GeneratorFunction, new Proxy({
+ get(target, propertyKey, receiver) {
+ getLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}, {
+ get(target, propertyKey, receiver) {
+ trapLog.push(propertyKey);
+ return Reflect.get(target, propertyKey, receiver);
+ }
+}));
+
+fn = Reflect.construct(GeneratorFunction, [], ProxiedConstructor);
+assertEqArray(trapLog, ["get"]);
+assertEqArray(getLog, ["prototype"]);
+assertEq(fn instanceof GeneratorFunction, true);
+assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Generators/delegating-yield-2.js b/js/src/tests/ecma_6/Generators/delegating-yield-2.js
index 918fb33e11..34cb3f4a9f 100644
--- a/js/src/tests/ecma_6/Generators/delegating-yield-2.js
+++ b/js/src/tests/ecma_6/Generators/delegating-yield-2.js
@@ -25,8 +25,8 @@ assertThrowsValue(function () { outer.throw(42) }, 42);
inner = g1();
outer = delegate(inner);
assertIteratorNext(outer, 1);
-inner.throw = function(e) { return e*2; };
-assertEq(84, outer.throw(42));
+inner.throw = function(e) { return { value: e*2 }; };
+assertEq(84, outer.throw(42).value);
assertIteratorDone(outer, undefined);
// Monkeypatching inner.next.
@@ -41,7 +41,9 @@ outer = delegate(inner);
assertIteratorNext(outer, 1);
delete GeneratorObjectPrototype.throw;
var outer_throw_42 = GeneratorObjectPrototype_throw.bind(outer, 42);
-assertThrowsValue(outer_throw_42, 42);
+// yield* protocol violation: no 'throw' method
+assertThrowsInstanceOf(outer_throw_42, TypeError);
+// Now done, so just throws.
assertThrowsValue(outer_throw_42, 42);
// Monkeypunch a different throw handler.
@@ -49,11 +51,11 @@ inner = g2();
outer = delegate(inner);
outer_throw_42 = GeneratorObjectPrototype_throw.bind(outer, 42);
assertIteratorNext(outer, 1);
-GeneratorObjectPrototype.throw = function(e) { return e*2; }
-assertEq(84, outer_throw_42());
-assertEq(84, outer_throw_42());
+GeneratorObjectPrototype.throw = function(e) { return { value: e*2 }; }
+assertEq(84, outer_throw_42().value);
+assertEq(84, outer_throw_42().value);
// This continues indefinitely.
-assertEq(84, outer_throw_42());
+assertEq(84, outer_throw_42().value);
assertIteratorDone(outer, undefined);
// The same, but restoring the original pre-monkey throw.
@@ -61,8 +63,8 @@ inner = g2();
outer = delegate(inner);
outer_throw_42 = GeneratorObjectPrototype_throw.bind(outer, 42);
assertIteratorNext(outer, 1);
-assertEq(84, outer_throw_42());
-assertEq(84, outer_throw_42());
+assertEq(84, outer_throw_42().value);
+assertEq(84, outer_throw_42().value);
GeneratorObjectPrototype.throw = GeneratorObjectPrototype_throw;
assertIteratorResult(outer_throw_42(), 42, false);
assertIteratorDone(outer, undefined);
diff --git a/js/src/tests/ecma_6/Generators/subclass.js b/js/src/tests/ecma_6/Generators/subclass.js
new file mode 100644
index 0000000000..f93f4df4db
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/subclass.js
@@ -0,0 +1,33 @@
+/* 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 GeneratorFunction = function*(){}.constructor;
+
+class MyGen extends GeneratorFunction {}
+
+// MyGen inherits from %GeneratorFunction%.
+assertEq(Object.getPrototypeOf(MyGen), GeneratorFunction);
+
+// MyGen.prototype inherits from %Generator%.
+assertEq(Object.getPrototypeOf(MyGen.prototype), GeneratorFunction.prototype);
+
+var fn = new MyGen("yield* [1, 2, 3]");
+
+// fn inherits from MyGen.prototype.
+assertEq(Object.getPrototypeOf(fn), MyGen.prototype);
+
+// fn.prototype inherits from %GeneratorPrototype%.
+assertEq(Object.getPrototypeOf(fn.prototype), GeneratorFunction.prototype.prototype);
+
+// Ensure the new generator function can be executed.
+var it = fn();
+
+// it inherits from fn.prototype.
+assertEq(Object.getPrototypeOf(it), fn.prototype);
+
+// Computes the expected result.
+assertEqArray([...it], [1, 2, 3]);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Generators/yield-iterator-close.js b/js/src/tests/ecma_6/Generators/yield-iterator-close.js
new file mode 100644
index 0000000000..970ad494d2
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/yield-iterator-close.js
@@ -0,0 +1,58 @@
+// Test that IteratorClose is called when a Generator is abruptly completed by
+// Generator.return.
+
+var returnCalled = 0;
+function* wrapNoThrow() {
+ let iter = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ return { value: 10, done: false };
+ },
+ return() {
+ returnCalled++;
+ return {};
+ }
+ };
+ for (const i of iter) {
+ yield i;
+ }
+}
+
+// Breaking calls Generator.return, which causes the yield above to resume with
+// an abrupt completion of kind "return", which then calls
+// iter.return.
+for (const i of wrapNoThrow()) {
+ break;
+}
+assertEq(returnCalled, 1);
+
+function* wrapThrow() {
+ let iter = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ return { value: 10, done: false };
+ },
+ return() {
+ throw 42;
+ }
+ };
+ for (const i of iter) {
+ yield i;
+ }
+}
+
+// Breaking calls Generator.return, which, like above, calls iter.return. If
+// iter.return throws, since the yield is resuming with an abrupt completion of
+// kind "return", the newly thrown value takes precedence over returning.
+assertThrowsValue(() => {
+ for (const i of wrapThrow()) {
+ break;
+ }
+}, 42);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Generators/yield-star-iterator-close.js b/js/src/tests/ecma_6/Generators/yield-star-iterator-close.js
new file mode 100644
index 0000000000..91ad31cb64
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/yield-star-iterator-close.js
@@ -0,0 +1,153 @@
+// Tests that the "return" method on iterators is called in yield*
+// expressions.
+
+function test() {
+ var returnCalled = 0;
+ var returnCalledExpected = 0;
+ var nextCalled = 0;
+ var nextCalledExpected = 0;
+ var throwCalled = 0;
+ var throwCalledExpected = 0;
+ var iterable = {};
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ nextCalled++;
+ return { done: false };
+ },
+ ret: function() {
+ returnCalled++;
+ return { done: true, value: "iter.return" };
+ }
+ });
+
+ function* y() {
+ yield* iterable;
+ }
+
+ // G.p.throw on an iterator without "throw" calls IteratorClose.
+ var g1 = y();
+ g1.next();
+ assertThrowsInstanceOf(function() {
+ g1.throw("foo");
+ }, TypeError);
+ assertEq(returnCalled, ++returnCalledExpected);
+ assertEq(nextCalled, ++nextCalledExpected);
+ g1.next();
+ assertEq(nextCalled, nextCalledExpected);
+
+ // G.p.return calls "return", and if the result.done is true, return the
+ // result.
+ var g2 = y();
+ g2.next();
+ var v2 = g2.return("test return");
+ assertEq(v2.done, true);
+ assertEq(v2.value, "iter.return");
+ assertEq(returnCalled, ++returnCalledExpected);
+ assertEq(nextCalled, ++nextCalledExpected);
+ g2.next();
+ assertEq(nextCalled, nextCalledExpected);
+
+ // G.p.return calls "return", and if the result.done is false, continue
+ // yielding.
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ nextCalled++;
+ return { done: false };
+ },
+ ret: function() {
+ returnCalled++;
+ return { done: false, value: "iter.return" };
+ }
+ });
+ var g3 = y();
+ g3.next();
+ var v3 = g3.return("test return");
+ assertEq(v3.done, false);
+ assertEq(v3.value, "iter.return");
+ assertEq(returnCalled, ++returnCalledExpected);
+ assertEq(nextCalled, ++nextCalledExpected);
+ g3.next();
+ assertEq(nextCalled, ++nextCalledExpected);
+
+ // G.p.return throwing does not re-call iter.return.
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ throw "in iter.return";
+ }
+ });
+ var g4 = y();
+ g4.next();
+ assertThrowsValue(function() {
+ g4.return("in test");
+ }, "in iter.return");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // G.p.return expects iter.return to return an Object.
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ return 42;
+ }
+ });
+ var g5 = y();
+ g5.next();
+ assertThrowsInstanceOf(function() {
+ g5.return("foo");
+ }, TypeError);
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // IteratorClose expects iter.return to return an Object.
+ var g6 = y();
+ g6.next();
+ var exc;
+ try {
+ g6.throw("foo");
+ } catch (e) {
+ exc = e;
+ } finally {
+ assertEq(exc instanceof TypeError, true);
+ // The message test is here because instanceof TypeError doesn't
+ // distinguish the non-Object return TypeError and the
+ // throw-method-is-not-defined iterator protocol error.
+ assertEq(exc.toString().indexOf("non-object") > 0, true);
+ }
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // G.p.return passes its argument to "return".
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function(x) {
+ assertEq(x, "in test");
+ returnCalled++;
+ return { done: true };
+ }
+ });
+ var g7 = y();
+ g7.next();
+ g7.return("in test");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // If a throw method is present, do not call "return".
+ iterable[Symbol.iterator] = makeIterator({
+ throw: function(e) {
+ throwCalled++;
+ throw e;
+ },
+ ret: function(x) {
+ returnCalled++;
+ return { done: true };
+ }
+ });
+ var g8 = y();
+ g8.next();
+ assertThrowsValue(function() {
+ g8.throw("foo");
+ }, "foo");
+ assertEq(throwCalled, ++throwCalledExpected);
+ assertEq(returnCalled, returnCalledExpected);
+}
+
+test();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Map/constructor-iterator-close.js b/js/src/tests/ecma_6/Map/constructor-iterator-close.js
new file mode 100644
index 0000000000..ba4bee4a74
--- /dev/null
+++ b/js/src/tests/ecma_6/Map/constructor-iterator-close.js
@@ -0,0 +1,253 @@
+var BUGNUMBER = 1180306;
+var summary = 'Map/Set/WeakMap/WeakSet constructor should close iterator on error';
+
+print(BUGNUMBER + ": " + summary);
+
+function test(ctors, { nextVal=undefined,
+ nextThrowVal=undefined,
+ modifier=undefined,
+ exceptionVal=undefined,
+ exceptionType=undefined,
+ closed=true }) {
+ function getIterable() {
+ let iterable = {
+ closed: false,
+ [Symbol.iterator]() {
+ let iterator = {
+ first: true,
+ next() {
+ if (this.first) {
+ this.first = false;
+ if (nextThrowVal)
+ throw nextThrowVal;
+ return nextVal;
+ }
+ return { value: undefined, done: true };
+ },
+ return() {
+ iterable.closed = true;
+ return {};
+ }
+ };
+ if (modifier)
+ modifier(iterator, iterable);
+
+ return iterator;
+ }
+ };
+ return iterable;
+ }
+
+ for (let ctor of ctors) {
+ let iterable = getIterable();
+ if (exceptionVal) {
+ let caught = false;
+ try {
+ new ctor(iterable);
+ } catch (e) {
+ assertEq(e, exceptionVal);
+ caught = true;
+ }
+ assertEq(caught, true);
+ } else if (exceptionType) {
+ assertThrowsInstanceOf(() => new ctor(iterable), exceptionType);
+ } else {
+ new ctor(iterable);
+ }
+ assertEq(iterable.closed, closed);
+ }
+}
+
+// == Error cases with close ==
+
+// ES 2017 draft 23.1.1.1 Map step 8.d.ii.
+// ES 2017 draft 23.3.1.1 WeakMap step 8.d.ii.
+test([Map, WeakMap], {
+ nextVal: { value: "non object", done: false },
+ exceptionType: TypeError,
+ closed: true,
+});
+
+// ES 2017 draft 23.1.1.1 Map step 8.f.
+// ES 2017 draft 23.3.1.1 WeakMap step 8.f.
+test([Map, WeakMap], {
+ nextVal: { value: { get 0() { throw "0 getter throws"; } }, done: false },
+ exceptionVal: "0 getter throws",
+ closed: true,
+});
+
+// ES 2017 draft 23.1.1.1 Map step 8.h.
+// ES 2017 draft 23.3.1.1 WeakMap step 8.h.
+test([Map, WeakMap], {
+ nextVal: { value: { 0: {}, get 1() { throw "1 getter throws"; } }, done: false },
+ exceptionVal: "1 getter throws",
+ closed: true,
+});
+
+// ES 2017 draft 23.1.1.1 Map step 8.j.
+// ES 2017 draft 23.3.1.1 WeakMap step 8.j.
+class MyMap extends Map {
+ set(k, v) {
+ throw "setter throws";
+ }
+}
+class MyWeakMap extends WeakMap {
+ set(k, v) {
+ throw "setter throws";
+ }
+}
+test([MyMap, MyWeakMap], {
+ nextVal: { value: [{}, {}], done: false },
+ exceptionVal: "setter throws",
+ closed: true,
+});
+
+// ES 2017 draft 23.2.1.1 Set step 8.e.
+// ES 2017 draft 23.4.1.1 WeakSet step 8.e.
+class MySet extends Set {
+ add(v) {
+ throw "adder throws";
+ }
+}
+class MyWeakSet extends WeakSet {
+ add(v) {
+ throw "adder throws";
+ }
+}
+test([MySet, MyWeakSet], {
+ nextVal: { value: {}, done: false },
+ exceptionVal: "adder throws",
+ closed: true,
+});
+
+// ES 2017 draft 7.4.6 step 3.
+// if GetMethod fails, the thrown value should be used.
+test([MyMap, MySet, MyWeakMap, MyWeakSet], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ throw "return getter throws";
+ }
+ });
+ },
+ exceptionVal: "return getter throws",
+ closed: true,
+});
+test([MyMap, MySet, MyWeakMap, MyWeakSet], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ return "non object";
+ }
+ });
+ },
+ exceptionType: TypeError,
+ closed: true,
+});
+test([MyMap, MySet, MyWeakMap, MyWeakSet], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ // Non callable.
+ return {};
+ }
+ });
+ },
+ exceptionType: TypeError,
+ closed: true,
+});
+
+// ES 2017 draft 7.4.6 steps 6.
+// if return method throws, the thrown value should be ignored.
+test([MyMap, MyWeakMap], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ throw "return throws";
+ };
+ },
+ exceptionVal: "setter throws",
+ closed: true,
+});
+test([MySet, MyWeakSet], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ throw "return throws";
+ };
+ },
+ exceptionVal: "adder throws",
+ closed: true,
+});
+
+test([MyMap, MyWeakMap], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ return "non object";
+ };
+ },
+ exceptionVal: "setter throws",
+ closed: true,
+});
+test([MySet, MyWeakSet], {
+ nextVal: { value: [{}, {}], done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ return "non object";
+ };
+ },
+ exceptionVal: "adder throws",
+ closed: true,
+});
+
+// == Error cases without close ==
+
+// ES 2017 draft 23.1.1.1 Map step 8.a.
+// ES 2017 draft 23.3.1.1 WeakMap step 8.a.
+// ES 2017 draft 23.2.1.1 Set step 8.a.
+// ES 2017 draft 23.4.1.1 WeakSet step 8.a.
+test([Map, WeakMap, Set, WeakSet], {
+ nextThrowVal: "next throws",
+ exceptionVal: "next throws",
+ closed: false,
+});
+test([Map, WeakMap, Set, WeakSet], {
+ nextVal: { value: {}, get done() { throw "done getter throws"; } },
+ exceptionVal: "done getter throws",
+ closed: false,
+});
+
+// ES 2017 draft 23.1.1.1 Map step 8.c.
+// ES 2017 draft 23.3.1.1 WeakMap step 8.c.
+// ES 2017 draft 23.2.1.1 Set step 8.c.
+// ES 2017 draft 23.4.1.1 WeakSet step 8.c.
+test([Map, WeakMap, Set, WeakSet], {
+ nextVal: { get value() { throw "value getter throws"; }, done: false },
+ exceptionVal: "value getter throws",
+ closed: false,
+});
+
+// == Successful cases ==
+
+test([Map, WeakMap], {
+ nextVal: { value: [{}, {}], done: false },
+ closed: false,
+});
+test([Set, WeakSet], {
+ nextVal: { value: {}, done: false },
+ closed: false,
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/Object/accessor-name.js b/js/src/tests/ecma_6/Object/accessor-name.js
index 1b5268e072..f238a2aefc 100644
--- a/js/src/tests/ecma_6/Object/accessor-name.js
+++ b/js/src/tests/ecma_6/Object/accessor-name.js
@@ -27,10 +27,9 @@ o = {get case() { }, set case(v) {}}
assertEq(name(o, "case", true), "get case");
assertEq(name(o, "case", false), "set case");
-// Congratulations on implementing these!
-assertEq(name({get ["a"]() {}}, "a", true), "");
-assertEq(name({get [123]() {}}, "123", true), "");
-assertEq(name({set ["a"](v) {}}, "a", false), "");
-assertEq(name({set [123](v) {}}, "123", false), "");
+assertEq(name({get ["a"]() {}}, "a", true), "get a");
+assertEq(name({get [123]() {}}, "123", true), "get 123");
+assertEq(name({set ["a"](v) {}}, "a", false), "set a");
+assertEq(name({set [123](v) {}}, "123", false), "set 123");
reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/Promise/iterator-close.js b/js/src/tests/ecma_6/Promise/iterator-close.js
new file mode 100644
index 0000000000..f17260d05b
--- /dev/null
+++ b/js/src/tests/ecma_6/Promise/iterator-close.js
@@ -0,0 +1,234 @@
+// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
+
+var BUGNUMBER = 1180306;
+var summary = 'Promise.{all,race} should close iterator on error';
+
+print(BUGNUMBER + ": " + summary);
+
+function test(ctor, props, { nextVal=undefined,
+ nextThrowVal=undefined,
+ modifier=undefined,
+ rejectReason=undefined,
+ rejectType=undefined,
+ closed=true }) {
+ function getIterable() {
+ let iterable = {
+ closed: false,
+ [Symbol.iterator]() {
+ let iterator = {
+ first: true,
+ next() {
+ if (this.first) {
+ this.first = false;
+ if (nextThrowVal)
+ throw nextThrowVal;
+ return nextVal;
+ }
+ return { value: undefined, done: true };
+ },
+ return() {
+ iterable.closed = true;
+ return {};
+ }
+ };
+ if (modifier)
+ modifier(iterator, iterable);
+
+ return iterator;
+ }
+ };
+ return iterable;
+ }
+ for (let prop of props) {
+ let iterable = getIterable();
+ let e;
+ ctor[prop](iterable).catch(e_ => { e = e_; });
+ drainJobQueue();
+ if(rejectType)
+ assertEq(e instanceof rejectType, true);
+ else
+ assertEq(e, rejectReason);
+ assertEq(iterable.closed, closed);
+ }
+}
+
+// == Error cases with close ==
+
+// ES 2017 draft 25.4.4.1.1 step 6.i.
+// ES 2017 draft 25.4.4.3.1 step 3.h.
+class MyPromiseStaticResolveGetterThrows extends Promise {
+ static get resolve() {
+ throw "static resolve getter throws";
+ }
+};
+test(MyPromiseStaticResolveGetterThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ rejectReason: "static resolve getter throws",
+ closed: true,
+});
+
+class MyPromiseStaticResolveThrows extends Promise {
+ static resolve() {
+ throw "static resolve throws";
+ }
+};
+test(MyPromiseStaticResolveThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ rejectReason: "static resolve throws",
+ closed: true,
+});
+
+// ES 2017 draft 25.4.4.1.1 step 6.q.
+// ES 2017 draft 25.4.4.3.1 step 3.i.
+class MyPromiseThenGetterThrows extends Promise {
+ static resolve() {
+ return {
+ get then() {
+ throw "then getter throws";
+ }
+ };
+ }
+};
+test(MyPromiseThenGetterThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ rejectReason: "then getter throws",
+ closed: true,
+});
+
+class MyPromiseThenThrows extends Promise {
+ static resolve() {
+ return {
+ then() {
+ throw "then throws";
+ }
+ };
+ }
+};
+test(MyPromiseThenThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ rejectReason: "then throws",
+ closed: true,
+});
+
+// ES 2017 draft 7.4.6 step 3.
+// if GetMethod fails, the thrown value should be used.
+test(MyPromiseThenThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ throw "return getter throws";
+ }
+ });
+ },
+ rejectReason: "return getter throws",
+ closed: true,
+});
+test(MyPromiseThenThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ return "non object";
+ }
+ });
+ },
+ rejectType: TypeError,
+ closed: true,
+});
+test(MyPromiseThenThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ modifier: (iterator, iterable) => {
+ Object.defineProperty(iterator, "return", {
+ get: function() {
+ iterable.closed = true;
+ // Non callable.
+ return {};
+ }
+ });
+ },
+ rejectType: TypeError,
+ closed: true,
+});
+
+// ES 2017 draft 7.4.6 steps 6.
+// if return method throws, the thrown value should be ignored.
+test(MyPromiseThenThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ throw "return throws";
+ };
+ },
+ rejectReason: "then throws",
+ closed: true,
+});
+
+test(MyPromiseThenThrows, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ modifier: (iterator, iterable) => {
+ iterator.return = function() {
+ iterable.closed = true;
+ return "non object";
+ };
+ },
+ rejectReason: "then throws",
+ closed: true,
+});
+
+// == Error cases without close ==
+
+// ES 2017 draft 25.4.4.1.1 step 6.a.
+test(Promise, ["all", "race"], {
+ nextThrowVal: "next throws",
+ rejectReason: "next throws",
+ closed: false,
+});
+
+test(Promise, ["all", "race"], {
+ nextVal: { value: {}, get done() { throw "done getter throws"; } },
+ rejectReason: "done getter throws",
+ closed: false,
+});
+
+// ES 2017 draft 25.4.4.1.1 step 6.e.
+test(Promise, ["all", "race"], {
+ nextVal: { get value() { throw "value getter throws"; }, done: false },
+ rejectReason: "value getter throws",
+ closed: false,
+});
+
+// ES 2017 draft 25.4.4.1.1 step 6.d.iii.2.
+let first = true;
+class MyPromiseResolveThrows extends Promise {
+ constructor(executer) {
+ if (first) {
+ first = false;
+ super((resolve, reject) => {
+ executer(() => {
+ throw "resolve throws";
+ }, reject);
+ });
+ return;
+ }
+ super(executer);
+ }
+};
+test(MyPromiseResolveThrows, ["all"], {
+ nextVal: { value: undefined, done: true },
+ rejectReason: "resolve throws",
+ closed: false,
+});
+
+// == Successful cases ==
+
+test(Promise, ["all", "race"], {
+ nextVal: { value: Promise.resolve(1), done: false },
+ closed: false,
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/RegExp/compile-lastIndex.js b/js/src/tests/ecma_6/RegExp/compile-lastIndex.js
index 80c820f43d..5bd7e0b983 100644
--- a/js/src/tests/ecma_6/RegExp/compile-lastIndex.js
+++ b/js/src/tests/ecma_6/RegExp/compile-lastIndex.js
@@ -17,15 +17,12 @@ print(BUGNUMBER + ": " + summary);
var regex = /foo/i;
-// Aside from making .lastIndex non-writable, this has two incidental effects
+// Aside from making .lastIndex non-writable, this has one incidental effect
// ubiquitously tested through the remainder of this test:
//
// * RegExp.prototype.compile will do everything it ordinarily does, BUT it
// will throw a TypeError when attempting to zero .lastIndex immediately
// before succeeding overall.
-// * RegExp.prototype.test for a non-global and non-sticky regular expression,
-// in case of a match, will return true (as normal). BUT if no match is
-// found, it will throw a TypeError when attempting to modify .lastIndex.
//
// Ain't it great?
Object.defineProperty(regex, "lastIndex", { value: 42, writable: false });
@@ -40,8 +37,8 @@ assertEq(regex.lastIndex, 42);
assertEq(regex.test("foo"), true);
assertEq(regex.test("FOO"), true);
-assertThrowsInstanceOf(() => regex.test("bar"), TypeError);
-assertThrowsInstanceOf(() => regex.test("BAR"), TypeError);
+assertEq(regex.test("bar"), false);
+assertEq(regex.test("BAR"), false);
assertThrowsInstanceOf(() => regex.compile("bar"), TypeError);
@@ -52,10 +49,10 @@ assertEq(regex.unicode, false);
assertEq(regex.sticky, false);
assertEq(Object.getOwnPropertyDescriptor(regex, "lastIndex").writable, false);
assertEq(regex.lastIndex, 42);
-assertThrowsInstanceOf(() => regex.test("foo"), TypeError);
-assertThrowsInstanceOf(() => regex.test("FOO"), TypeError);
+assertEq(regex.test("foo"), false);
+assertEq(regex.test("FOO"), false);
assertEq(regex.test("bar"), true);
-assertThrowsInstanceOf(() => regex.test("BAR"), TypeError);
+assertEq(regex.test("BAR"), false);
assertThrowsInstanceOf(() => regex.compile("^baz", "m"), TypeError);
@@ -66,19 +63,16 @@ assertEq(regex.unicode, false);
assertEq(regex.sticky, false);
assertEq(Object.getOwnPropertyDescriptor(regex, "lastIndex").writable, false);
assertEq(regex.lastIndex, 42);
-assertThrowsInstanceOf(() => regex.test("foo"), TypeError);
-assertThrowsInstanceOf(() => regex.test("FOO"), TypeError);
-assertThrowsInstanceOf(() => regex.test("bar"), TypeError);
-assertThrowsInstanceOf(() => regex.test("BAR"), TypeError);
+assertEq(regex.test("foo"), false);
+assertEq(regex.test("FOO"), false);
+assertEq(regex.test("bar"), false);
+assertEq(regex.test("BAR"), false);
assertEq(regex.test("baz"), true);
-assertThrowsInstanceOf(() => regex.test("BAZ"), TypeError);
-assertThrowsInstanceOf(() => regex.test("012345678901234567890123456789012345678901baz"),
- TypeError);
+assertEq(regex.test("BAZ"), false);
+assertEq(regex.test("012345678901234567890123456789012345678901baz"), false);
assertEq(regex.test("012345678901234567890123456789012345678901\nbaz"), true);
-assertThrowsInstanceOf(() => regex.test("012345678901234567890123456789012345678901BAZ"),
- TypeError);
-assertThrowsInstanceOf(() => regex.test("012345678901234567890123456789012345678901\nBAZ"),
- TypeError);
+assertEq(regex.test("012345678901234567890123456789012345678901BAZ"), false);
+assertEq(regex.test("012345678901234567890123456789012345678901\nBAZ"), false);
/******************************************************************************/
diff --git a/js/src/tests/ecma_6/RegExp/compile-symbol.js b/js/src/tests/ecma_6/RegExp/compile-symbol.js
new file mode 100644
index 0000000000..9eea1124c8
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/compile-symbol.js
@@ -0,0 +1,14 @@
+/* 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/. */
+
+for (let sym of [Symbol.iterator, Symbol(), Symbol("description")]) {
+ let re = /a/;
+
+ assertEq(re.source, "a");
+ assertThrowsInstanceOf(() => re.compile(sym), TypeError);
+ assertEq(re.source, "a");
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/RegExp/constructor-symbol.js b/js/src/tests/ecma_6/RegExp/constructor-symbol.js
new file mode 100644
index 0000000000..503d7e5a85
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/constructor-symbol.js
@@ -0,0 +1,14 @@
+/* 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/. */
+
+for (let sym of [Symbol.iterator, Symbol(), Symbol("description")]) {
+ assertThrowsInstanceOf(() => RegExp(sym), TypeError);
+ assertThrowsInstanceOf(() => new RegExp(sym), TypeError);
+
+ assertThrowsInstanceOf(() => RegExp(sym, "g"), TypeError);
+ assertThrowsInstanceOf(() => new RegExp(sym, "g"), TypeError);
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/RegExp/match-local-tolength-recompilation.js b/js/src/tests/ecma_6/RegExp/match-local-tolength-recompilation.js
new file mode 100644
index 0000000000..9a992f81f4
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/match-local-tolength-recompilation.js
@@ -0,0 +1,75 @@
+// Side-effects when calling ToLength(regExp.lastIndex) in
+// RegExp.prototype[@@match] for non-global RegExp can recompile the RegExp.
+
+for (var flag of ["", "y"]) {
+ var regExp = new RegExp("a", flag);
+
+ regExp.lastIndex = {
+ valueOf() {
+ regExp.compile("b");
+ return 0;
+ }
+ };
+
+ var result = regExp[Symbol.match]("b");
+ assertEq(result !== null, true);
+}
+
+// Recompilation modifies flag:
+// Case 1: Adds global flag, validate by checking lastIndex.
+var regExp = new RegExp("a", "");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is now in global mode, RegExpBuiltinExec should update the
+ // lastIndex property to reflect last match.
+ regExp.compile("a", "g");
+ return 0;
+ }
+};
+regExp[Symbol.match]("a");
+assertEq(regExp.lastIndex, 1);
+
+// Case 2: Removes sticky flag with match, validate by checking lastIndex.
+var regExp = new RegExp("a", "y");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is no longer sticky, RegExpBuiltinExec shouldn't modify the
+ // lastIndex property.
+ regExp.compile("a", "");
+ regExp.lastIndex = 9000;
+ return 0;
+ }
+};
+regExp[Symbol.match]("a");
+assertEq(regExp.lastIndex, 9000);
+
+// Case 3.a: Removes sticky flag without match, validate by checking lastIndex.
+var regExp = new RegExp("a", "y");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is no longer sticky, RegExpBuiltinExec shouldn't modify the
+ // lastIndex property.
+ regExp.compile("b", "");
+ regExp.lastIndex = 9001;
+ return 0;
+ }
+};
+regExp[Symbol.match]("a");
+assertEq(regExp.lastIndex, 9001);
+
+// Case 3.b: Removes sticky flag without match, validate by checking lastIndex.
+var regExp = new RegExp("a", "y");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is no longer sticky, RegExpBuiltinExec shouldn't modify the
+ // lastIndex property.
+ regExp.compile("b", "");
+ regExp.lastIndex = 9002;
+ return 10000;
+ }
+};
+regExp[Symbol.match]("a");
+assertEq(regExp.lastIndex, 9002);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/RegExp/prototype.js b/js/src/tests/ecma_6/RegExp/prototype.js
new file mode 100644
index 0000000000..528142ab0c
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/prototype.js
@@ -0,0 +1,31 @@
+const t = RegExp.prototype;
+
+const properties = "toSource,toString,compile,exec,test," +
+ "flags,global,ignoreCase,multiline,source,sticky,unicode," +
+ "constructor," +
+ "Symbol(Symbol.match),Symbol(Symbol.replace),Symbol(Symbol.search),Symbol(Symbol.split)";
+assertEq(Reflect.ownKeys(t).map(String).toString(), properties);
+
+
+// Invoking getters on the prototype should not throw
+function getter(name) {
+ return Object.getOwnPropertyDescriptor(t, name).get.call(t);
+}
+
+assertEq(getter("flags"), "");
+assertEq(getter("global"), undefined);
+assertEq(getter("ignoreCase"), undefined);
+assertEq(getter("multiline"), undefined);
+assertEq(getter("source"), "(?:)");
+assertEq(getter("sticky"), undefined);
+assertEq(getter("unicode"), undefined);
+
+assertEq(t.toString(), "/(?:)/");
+
+// The methods don't work with the prototype
+assertThrowsInstanceOf(() => t.compile("b", "i"), TypeError);
+assertThrowsInstanceOf(() => t.test("x"), TypeError);
+assertThrowsInstanceOf(() => t.exec("x"), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/RegExp/replace-local-tolength-lastindex.js b/js/src/tests/ecma_6/RegExp/replace-local-tolength-lastindex.js
new file mode 100644
index 0000000000..7ba840e000
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/replace-local-tolength-lastindex.js
@@ -0,0 +1,22 @@
+// RegExp.prototype[@@replace] always executes ToLength(regExp.lastIndex) for
+// non-global RegExps.
+
+for (var flag of ["", "g", "y", "gy"]) {
+ var regExp = new RegExp("a", flag);
+
+ var called = false;
+ regExp.lastIndex = {
+ valueOf() {
+ assertEq(called, false);
+ called = true;
+ return 0;
+ }
+ };
+
+ assertEq(called, false);
+ regExp[Symbol.replace]("");
+ assertEq(called, !flag.includes("g"));
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/RegExp/replace-local-tolength-recompilation.js b/js/src/tests/ecma_6/RegExp/replace-local-tolength-recompilation.js
new file mode 100644
index 0000000000..e03177286f
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/replace-local-tolength-recompilation.js
@@ -0,0 +1,75 @@
+// Side-effects when calling ToLength(regExp.lastIndex) in
+// RegExp.prototype[@@replace] for non-global RegExp can recompile the RegExp.
+
+for (var flag of ["", "y"]) {
+ var regExp = new RegExp("a", flag);
+
+ regExp.lastIndex = {
+ valueOf() {
+ regExp.compile("b");
+ return 0;
+ }
+ };
+
+ var result = regExp[Symbol.replace]("b", "pass");
+ assertEq(result, "pass");
+}
+
+// Recompilation modifies flag:
+// Case 1: Adds global flag, validate by checking lastIndex.
+var regExp = new RegExp("a", "");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is now in global mode, RegExpBuiltinExec should update the
+ // lastIndex property to reflect last match.
+ regExp.compile("a", "g");
+ return 0;
+ }
+};
+regExp[Symbol.replace]("a", "");
+assertEq(regExp.lastIndex, 1);
+
+// Case 2: Removes sticky flag with match, validate by checking lastIndex.
+var regExp = new RegExp("a", "y");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is no longer sticky, RegExpBuiltinExec shouldn't modify the
+ // lastIndex property.
+ regExp.compile("a", "");
+ regExp.lastIndex = 9000;
+ return 0;
+ }
+};
+regExp[Symbol.replace]("a", "");
+assertEq(regExp.lastIndex, 9000);
+
+// Case 3.a: Removes sticky flag without match, validate by checking lastIndex.
+var regExp = new RegExp("a", "y");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is no longer sticky, RegExpBuiltinExec shouldn't modify the
+ // lastIndex property.
+ regExp.compile("b", "");
+ regExp.lastIndex = 9001;
+ return 0;
+ }
+};
+regExp[Symbol.replace]("a", "");
+assertEq(regExp.lastIndex, 9001);
+
+// Case 3.b: Removes sticky flag without match, validate by checking lastIndex.
+var regExp = new RegExp("a", "y");
+regExp.lastIndex = {
+ valueOf() {
+ // |regExp| is no longer sticky, RegExpBuiltinExec shouldn't modify the
+ // lastIndex property.
+ regExp.compile("b", "");
+ regExp.lastIndex = 9002;
+ return 10000;
+ }
+};
+regExp[Symbol.replace]("a", "");
+assertEq(regExp.lastIndex, 9002);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/RegExp/search-trace.js b/js/src/tests/ecma_6/RegExp/search-trace.js
index ef14514c65..fc6bee754c 100644
--- a/js/src/tests/ecma_6/RegExp/search-trace.js
+++ b/js/src/tests/ecma_6/RegExp/search-trace.js
@@ -56,6 +56,7 @@ assertEq(log,
"get:lastIndex," +
"set:lastIndex," +
"get:exec,call:exec," +
+ "get:lastIndex," +
"set:lastIndex," +
"get:result[index],");
@@ -70,6 +71,7 @@ assertEq(log,
"get:lastIndex," +
"set:lastIndex," +
"get:exec,call:exec," +
+ "get:lastIndex," +
"set:lastIndex,");
if (typeof reportCompare === "function")
diff --git a/js/src/tests/ecma_6/Statements/for-inof-finally.js b/js/src/tests/ecma_6/Statements/for-inof-finally.js
new file mode 100644
index 0000000000..e1f0c77e12
--- /dev/null
+++ b/js/src/tests/ecma_6/Statements/for-inof-finally.js
@@ -0,0 +1,78 @@
+var BUGNUMBER = 1332881;
+var summary =
+ "Leaving for-in and try should handle stack value in correct order";
+
+print(BUGNUMBER + ": " + summary);
+
+var called = 0;
+function reset() {
+ called = 0;
+}
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 10, done: false };
+ },
+ return() {
+ called++;
+ return {};
+ }
+ };
+ }
+};
+
+var a = (function () {
+ for (var x in [0]) {
+ try {} finally {
+ return 11;
+ }
+ }
+})();
+assertEq(a, 11);
+
+reset();
+var b = (function () {
+ for (var x of obj) {
+ try {} finally {
+ return 12;
+ }
+ }
+})();
+assertEq(called, 1);
+assertEq(b, 12);
+
+reset();
+var c = (function () {
+ for (var x in [0]) {
+ for (var y of obj) {
+ try {} finally {
+ return 13;
+ }
+ }
+ }
+})();
+assertEq(called, 1);
+assertEq(c, 13);
+
+reset();
+var d = (function () {
+ for (var x in [0]) {
+ for (var y of obj) {
+ try {} finally {
+ for (var z in [0]) {
+ for (var w of obj) {
+ try {} finally {
+ return 14;
+ }
+ }
+ }
+ }
+ }
+ }
+})();
+assertEq(called, 2);
+assertEq(d, 14);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_6/Statements/for-of-iterator-close-throw.js b/js/src/tests/ecma_6/Statements/for-of-iterator-close-throw.js
new file mode 100644
index 0000000000..1974e416be
--- /dev/null
+++ b/js/src/tests/ecma_6/Statements/for-of-iterator-close-throw.js
@@ -0,0 +1,35 @@
+function test() {
+ var returnCalled = 0;
+ var returnCalledExpected = 0;
+ var catchEntered = 0;
+ var finallyEntered = 0;
+ var finallyEnteredExpected = 0;
+ var iterable = {};
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ throw 42;
+ }
+ });
+
+ // inner try cannot catch IteratorClose throwing
+ assertThrowsValue(function() {
+ for (var x of iterable) {
+ try {
+ return;
+ } catch (e) {
+ catchEntered++;
+ } finally {
+ finallyEntered++;
+ }
+ }
+ }, 42);
+ assertEq(returnCalled, ++returnCalledExpected);
+ assertEq(catchEntered, 0);
+ assertEq(finallyEntered, ++finallyEnteredExpected);
+}
+
+test();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Statements/for-of-iterator-close.js b/js/src/tests/ecma_6/Statements/for-of-iterator-close.js
new file mode 100644
index 0000000000..b28895d8fe
--- /dev/null
+++ b/js/src/tests/ecma_6/Statements/for-of-iterator-close.js
@@ -0,0 +1,102 @@
+// Tests that IteratorReturn is called when a for-of loop has an abrupt
+// completion value during non-iterator code.
+
+function test() {
+ var returnCalled = 0;
+ var returnCalledExpected = 0;
+ var iterable = {};
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ return {};
+ }
+ });
+
+ // break calls iter.return
+ for (var x of iterable)
+ break;
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in body calls iter.return
+ assertThrowsValue(function() {
+ for (var x of iterable)
+ throw "in body";
+ }, "in body");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in lhs ref calls iter.return
+ function throwlhs() {
+ throw "in lhs";
+ }
+ assertThrowsValue(function() {
+ for ((throwlhs()) of iterable)
+ continue;
+ }, "in lhs");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in iter.return doesn't re-call iter.return
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ throw "in iter.return";
+ }
+ });
+ assertThrowsValue(function() {
+ for (var x of iterable)
+ break;
+ }, "in iter.return");
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // throw in iter.next doesn't call IteratorClose
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ throw "in next";
+ }
+ });
+ assertThrowsValue(function() {
+ for (var x of iterable)
+ break;
+ }, "in next");
+ assertEq(returnCalled, returnCalledExpected);
+
+ // "return" must return an Object.
+ iterable[Symbol.iterator] = makeIterator({
+ ret: function() {
+ returnCalled++;
+ return 42;
+ }
+ });
+ assertThrowsInstanceOf(function() {
+ for (var x of iterable)
+ break;
+ }, TypeError);
+ assertEq(returnCalled, ++returnCalledExpected);
+
+ // continue doesn't call iter.return for the loop it's continuing
+ var i = 0;
+ iterable[Symbol.iterator] = makeIterator({
+ next: function() {
+ return { done: i++ > 5 };
+ },
+ ret: function() {
+ returnCalled++;
+ return {};
+ }
+ });
+ for (var x of iterable)
+ continue;
+ assertEq(returnCalled, returnCalledExpected);
+
+ // continue does call iter.return for loops it skips
+ i = 0;
+ L: do {
+ for (var x of iterable)
+ continue L;
+ } while (false);
+ assertEq(returnCalled, ++returnCalledExpected);
+}
+
+test();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js b/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js
index 8e0a05fb50..e4b5f46029 100644
--- a/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js
+++ b/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js
@@ -98,7 +98,7 @@ const otherIdContinue = [
0x19DA, // NEW TAI LUE THAM DIGIT ONE, Gc=No
];
-for (let ident of [...idStart, ...otherIdStart]) {
+for (let ident of [...idStart, ...otherIdStart, ...idStartSupplemental]) {
for (let count of leadingZeros) {
let zeros = "0".repeat(count);
eval(`
@@ -108,20 +108,13 @@ for (let ident of [...idStart, ...otherIdStart]) {
}
}
-// Move this to the loop above when Bug 1197230 is fixed.
-for (let ident of [...idStartSupplemental]) {
- for (let zeros of leadingZeros) {
- assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError);
- }
-}
-
for (let ident of [...idContinue, ...idContinueSupplemental, ...otherIdContinue]) {
for (let zeros of leadingZeros) {
assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError);
}
}
-for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinue]) {
+for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinue, ...idStartSupplemental, ...idContinueSupplemental]) {
for (let zeros of leadingZeros) {
eval(`
let A\\u{${zeros}${ident.toString(16)}} = 123;
@@ -130,13 +123,6 @@ for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinu
}
}
-// Move this to the loop above when Bug 1197230 is fixed.
-for (let ident of [...idStartSupplemental, ...idContinueSupplemental]) {
- for (let zeros of leadingZeros) {
- assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError);
- }
-}
-
const notIdentifiers = [
0x0000, // NULL, Gc=Cc
diff --git a/js/src/tests/ecma_6/shell.js b/js/src/tests/ecma_6/shell.js
index 06be6f2db6..756da9f36c 100644
--- a/js/src/tests/ecma_6/shell.js
+++ b/js/src/tests/ecma_6/shell.js
@@ -3,21 +3,43 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(global) {
- /** Yield every permutation of the elements in some array. */
- global.Permutations = function* Permutations(items) {
- if (items.length == 0) {
- yield [];
- } else {
- items = items.slice(0);
- for (let i = 0; i < items.length; i++) {
- let swap = items[0];
- items[0] = items[i];
- items[i] = swap;
- for (let e of Permutations(items.slice(1, items.length)))
- yield [items[0]].concat(e);
- }
- }
- };
+ /** Yield every permutation of the elements in some array. */
+ global.Permutations = function* Permutations(items) {
+ if (items.length == 0) {
+ yield [];
+ } else {
+ items = items.slice(0);
+ for (let i = 0; i < items.length; i++) {
+ let swap = items[0];
+ items[0] = items[i];
+ items[i] = swap;
+ for (let e of Permutations(items.slice(1, items.length)))
+ yield [items[0]].concat(e);
+ }
+ }
+ };
+
+ /** Make an iterator with a return method. */
+ global.makeIterator = function makeIterator(overrides) {
+ var throwMethod;
+ if (overrides && overrides.throw)
+ throwMethod = overrides.throw;
+ var iterator = {
+ throw: throwMethod,
+ next: function(x) {
+ if (overrides && overrides.next)
+ return overrides.next(x);
+ return { done: false };
+ },
+ return: function(x) {
+ if (overrides && overrides.ret)
+ return overrides.ret(x);
+ return { done: true };
+ }
+ };
+
+ return function() { return iterator; };
+ };
})(this);
if (typeof assertThrowsInstanceOf === 'undefined') {