summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/basic/destructuring-iterator.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/basic/destructuring-iterator.js')
-rw-r--r--js/src/jit-test/tests/basic/destructuring-iterator.js124
1 files changed, 124 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/basic/destructuring-iterator.js b/js/src/jit-test/tests/basic/destructuring-iterator.js
new file mode 100644
index 0000000000..ca65930242
--- /dev/null
+++ b/js/src/jit-test/tests/basic/destructuring-iterator.js
@@ -0,0 +1,124 @@
+
+load(libdir + 'asserts.js');
+load(libdir + 'iteration.js');
+load(libdir + 'eqArrayHelper.js');
+
+// throw on non-iterables
+assertThrowsInstanceOf(() => { [a, b, c] = {0: 0, 1: 1, 2: 2} }, TypeError);
+
+var nextcalls = 0, donecalls = 0, valuecalls = 0;
+var doneafter = 0;
+var iterable = {};
+iterable[Symbol.iterator] = function () {
+ return {
+ next: function () {
+ assertEq(arguments.length, 0, 'iterator.next() should be called with no arguments');
+ nextcalls++;
+ return {
+ get done() {
+ donecalls++;
+ return --doneafter < 0;
+ },
+ get value() {
+ valuecalls++;
+ return valuecalls;
+ }
+ };
+ }
+ }
+};
+
+function assertIterable(expectCalls, fn, expectResult) {
+ [nextcalls, donecalls, valuecalls, doneafter] = [0,0,0, expectCalls[3]];
+ assertEqArray(fn(iterable), expectResult);
+ assertEq(nextcalls, expectCalls[0], 'calls to iterator.next()');
+ assertEq(donecalls, expectCalls[1], 'getting iterator.next().done');
+ assertEq(valuecalls, expectCalls[2], 'getting iterator.next().value');
+}
+
+assertIterable([1,1,1,1],
+ it => { var [a] = it; return [a]; },
+ [1]);
+assertIterable([2,2,1,1],
+ it => { var [a,b,c] = it; return [a,b,c]; },
+ [1,undefined,undefined]);
+assertIterable([2,2,1,1],
+ it => { var [a,b,...rest] = it; return [a,b,...rest]; },
+ [1,undefined]);
+assertIterable([5,5,4,4],
+ it => { var [,,...rest] = it; return rest; },
+ [3,4]);
+
+// the iterator should be exhausted before any error is thrown
+assertIterable([5,5,4,4],
+ it => {
+ assertThrowsInstanceOf(function () {
+ "use strict";
+ [...{0: "".x}] = it;
+ }, TypeError);
+ return [];
+ },
+ []);
+
+var arraycalls = 0;
+var ArrayIterator = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function () {
+ arraycalls++;
+ return ArrayIterator.apply(this, arguments);
+};
+// [...rest] should not call Array#@@iterator for the LHS
+var [...rest] = iterable;
+assertEq(arraycalls, 0, 'calls to Array#@@iterator');
+// [...[...rest]] should do so, since it creates an implicit array for the
+// first rest pattern, then destructures that again using @@iterator() for the
+// second rest pattern.
+var [...[...rest]] = iterable;
+assertEq(arraycalls, 1, 'calls to Array#@@iterator');
+
+// loop `fn` a few times, to get it JIT-compiled
+function loop(fn) {
+ var i = 1e4;
+ while (i--) fn();
+}
+
+loop(() => { doneafter = 4; var [a] = iterable; return a; });
+loop(() => { doneafter = 4; var [a,b,...[...rest]] = iterable; return rest; });
+
+
+// destructuring assignment should always use iterators and not optimize
+// to a "group assignment"
+delete Array.prototype[Symbol.iterator];
+assertThrowsInstanceOf(() => { var [a,b] = [1,2]; }, TypeError);
+Array.prototype[Symbol.iterator] = ArrayIterator;
+
+// observe the binding order
+a = undefined, b = undefined, c = undefined;
+var obj = {};
+obj[Symbol.iterator] = function* () {
+ // normal fields should be initialized right after |.next()|
+ yield 1;
+ assertEq(a, 1);
+ yield 2;
+ yield 3;
+ assertEq(b, 3);
+ yield 4;
+ yield 5;
+ // rest should be initialized after the iterator is exhausted
+ assertEq(c, undefined);
+};
+[a, , b, ...c] = obj;
+assertEqArray(c, [4,5]);
+
+// a throw inside the destructuring of the "catch" value should not enter
+// the "catch" block
+
+assertThrowsValue(function () {
+ try {
+ Array.prototype[Symbol.iterator] = function () { throw 'from iterator'; };
+ throw [1, 2];
+ } catch ([x, y]) {
+ throw 'not reached';
+ }
+}, 'from iterator');
+Array.prototype[Symbol.iterator] = ArrayIterator;
+