| // Copyright 2016 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| function* g() { yield 42; return 88 }; | |
| // Return method is "undefined". | |
| { | |
| g.prototype.return = null; | |
| assertEquals(undefined, (() => { | |
| for (var x of g()) { break; } | |
| })()); | |
| assertEquals(undefined, (() => { | |
| for (let x of g()) { break; } | |
| })()); | |
| assertEquals(undefined, (() => { | |
| for (const x of g()) { break; } | |
| })()); | |
| assertEquals(undefined, (() => { | |
| for (x of g()) { break; } | |
| })()); | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { throw 42; } | |
| }, 42); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { throw 42; } | |
| }, 42); | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { throw 42; } | |
| }, 42); | |
| assertThrowsEquals(() => { | |
| for (x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals(42, (() => { | |
| for (var x of g()) { return 42; } | |
| })()); | |
| assertEquals(42, (() => { | |
| for (let x of g()) { return 42; } | |
| })()); | |
| assertEquals(42, (() => { | |
| for (const x of g()) { return 42; } | |
| })()); | |
| assertEquals(42, (() => { | |
| for (x of g()) { return 42; } | |
| })()); | |
| assertEquals(42, eval('for (var x of g()) { x; }')); | |
| assertEquals(42, eval('for (let x of g()) { x; }')); | |
| assertEquals(42, eval('for (const x of g()) { x; }')); | |
| assertEquals(42, eval('for (x of g()) { x; }')); | |
| assertEquals(42, (() => { | |
| var [x] = g(); return x; | |
| })()); | |
| assertEquals(42, (() => { | |
| let [x] = g(); return x; | |
| })()); | |
| assertEquals(42, (() => { | |
| const [x] = g(); return x; | |
| })()); | |
| assertEquals(42, (() => { | |
| [x] = g(); return x; | |
| })()); | |
| assertEquals(42, | |
| (([x]) => x)(g()) | |
| ); | |
| } | |
| // Return method is not callable. | |
| { | |
| g.prototype.return = 666; | |
| assertThrows(() => { | |
| for (var x of g()) { break; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (let x of g()) { break; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (const x of g()) { break; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (x of g()) { break; } | |
| }, TypeError); | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { throw 666; } | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { throw 666; } | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { throw 666; } | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (x of g()) { throw 666; } | |
| }, 666); | |
| assertThrows(() => { | |
| for (var x of g()) { return 666; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (let x of g()) { return 666; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (const x of g()) { return 666; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (x of g()) { return 666; } | |
| }, TypeError); | |
| assertEquals(42, eval('for (var x of g()) { x; }')); | |
| assertEquals(42, eval('for (let x of g()) { x; }')); | |
| assertEquals(42, eval('for (const x of g()) { x; }')); | |
| assertEquals(42, eval('for (x of g()) { x; }')); | |
| assertThrows(() => { | |
| var [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| let [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| const [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| (([x]) => x)(g()); | |
| }, TypeError); | |
| } | |
| // Return method does not return an object. | |
| { | |
| g.prototype.return = () => 666; | |
| assertThrows(() => { | |
| for (var x of g()) { break; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (let x of g()) { break; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (const x of g()) { break; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (x of g()) { break; } | |
| }, TypeError); | |
| // Throw from the body of a for loop 'wins' vs throw | |
| // originating from a bad 'return' value. | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { throw 666; } | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { throw 666; } | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { throw 666; } | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (x of g()) { throw 666; } | |
| }, 666); | |
| assertThrows(() => { | |
| for (var x of g()) { return 666; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (let x of g()) { return 666; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (const x of g()) { return 666; } | |
| }, TypeError); | |
| assertThrows(() => { | |
| for (x of g()) { return 666; } | |
| }, TypeError); | |
| assertEquals(42, eval('for (var x of g()) { x; }')); | |
| assertEquals(42, eval('for (let x of g()) { x; }')); | |
| assertEquals(42, eval('for (const x of g()) { x; }')); | |
| assertEquals(42, eval('for (x of g()) { x; }')); | |
| assertThrows(() => { | |
| var [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| let [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| const [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| [x] = g(); return x; | |
| }, TypeError); | |
| assertThrows(() => { | |
| (([x]) => x)(g()); | |
| }, TypeError); | |
| } | |
| // Return method returns an object. | |
| { | |
| let log = []; | |
| g.prototype.return = (...args) => { log.push(args); return {} }; | |
| log = []; | |
| for (var x of g()) { break; } | |
| assertEquals([[]], log); | |
| log = []; | |
| for (let x of g()) { break; } | |
| assertEquals([[]], log); | |
| log = []; | |
| for (const x of g()) { break; } | |
| assertEquals([[]], log); | |
| log = []; | |
| for (x of g()) { break; } | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| for (var x of g()) { return 42; } | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| for (let x of g()) { return 42; } | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| for (const x of g()) { return 42; } | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| for (x of g()) { return 42; } | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, eval('for (var x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, eval('for (let x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, eval('for (const x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, eval('for (x of g()) { x; }')); | |
| assertEquals([], log); | |
| // Even if doing the assignment throws, still call return | |
| log = []; | |
| x = { set attr(_) { throw 1234; } }; | |
| assertThrowsEquals(() => { | |
| for (x.attr of g()) { throw 456; } | |
| }, 1234); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| var [x] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| let [x] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| const [x] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| [x] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertEquals(42, | |
| (([x]) => x)(g()) | |
| ); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| var [x,] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| let [x,] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| const [x,] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| [x,] = g(); return x; | |
| })()); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertEquals(42, | |
| (([x,]) => x)(g()) | |
| ); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| var [x,,] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| let [x,,] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| const [x,,] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, (() => { | |
| [x,,] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals(42, | |
| (([x,,]) => x)(g()) | |
| ); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| var [x, y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| let [x, y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| const [x, y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| [x, y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals([42, undefined], | |
| (([x, y]) => [x, y])(g()) | |
| ); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| var [...x] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| let [...x] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| const [...x] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| [...x] = g(); return x; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals([42], | |
| (([...x]) => x)(g()) | |
| ); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, []], (() => { | |
| var [x, ...y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, []], (() => { | |
| let [x, ...y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, []], (() => { | |
| const [x, ...y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, []], (() => { | |
| [x, ...y] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals([42, []], | |
| (([x, ...y]) => [x, y])(g()) | |
| ); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| var [] = g(); return []; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| let [] = g(); return []; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| const [] = g(); return []; | |
| })()); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| [] = g(); return []; | |
| })()); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertEquals([], | |
| (([]) => [])(g()) | |
| ); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| var [...[]] = g(); return []; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| let [...[]] = g(); return []; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| const [...[]] = g(); return []; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([], (() => { | |
| [...[]] = g(); return []; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals([], | |
| (([...[]]) => [])(g()) | |
| ); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| var [...[x]] = g(); return [x]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| let [...[x]] = g(); return [x]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| const [...[x]] = g(); return [x]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42], (() => { | |
| [...[x]] = g(); return [x]; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals([42], | |
| (([...[x]]) => [x])(g()) | |
| ); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| var [...[x, y]] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| let [...[x, y]] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| const [...[x, y]] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals([42, undefined], (() => { | |
| [...[x, y]] = g(); return [x, y]; | |
| })()); | |
| assertEquals([], log); | |
| log = [] | |
| assertEquals([42, undefined], | |
| (([...[x, y]]) => [x, y])(g()) | |
| ); | |
| assertEquals([], log); | |
| log = [] | |
| assertThrowsEquals(() => { | |
| let x = { set foo(_) { throw 666; } }; | |
| [x.foo] = g(); | |
| }, 666); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertThrows(() => { | |
| var [[]] = g(); | |
| }, TypeError); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertThrows(() => { | |
| let [[]] = g(); | |
| }, TypeError); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertThrows(() => { | |
| const [[]] = g(); | |
| }, TypeError); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertThrows(() => { | |
| [[]] = g(); | |
| }, TypeError); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertThrows(() => { | |
| (([[]]) => 0)(g()); | |
| }, TypeError); | |
| assertEquals([[]], log); | |
| log = [] | |
| assertThrows(() => { | |
| var [...[[]]] = g(); | |
| }, TypeError); | |
| assertEquals([], log); | |
| log = [] | |
| assertThrows(() => { | |
| let [...[[]]] = g(); | |
| }, TypeError); | |
| assertEquals([], log); | |
| log = [] | |
| assertThrows(() => { | |
| const [...[[]]] = g(); | |
| }, TypeError); | |
| assertEquals([], log); | |
| log = [] | |
| assertThrows(() => { | |
| [...[[]]] = g(); | |
| }, TypeError); | |
| assertEquals([], log); | |
| log = [] | |
| assertThrows(() => { | |
| (([...[[]]]) => 0)(g()); | |
| }, TypeError); | |
| assertEquals([], log); | |
| { | |
| let backup = Array.prototype[Symbol.iterator]; | |
| Array.prototype[Symbol.iterator] = () => g(); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| var [x, ...[y]] = [1, 2, 3] | |
| }); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| let [x, ...[y]] = [1, 2, 3]; | |
| }); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| const [x, ...[y]] = [1, 2, 3]; | |
| }); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| (([x, ...[y]]) => {})([1, 2, 3]); | |
| }); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertThrows(() => { | |
| var [x, ...[[]]] = [1, 2, 3]; | |
| }, TypeError); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertThrows(() => { | |
| let [x, ...[[]]] = [1, 2, 3]; | |
| }, TypeError); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertThrows(() => { | |
| const [x, ...[[]]] = [1, 2, 3]; | |
| }, TypeError); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertThrows(() => { | |
| (([x, ...[[]]]) => {})([1, 2, 3]); | |
| }, TypeError); | |
| assertEquals(log, [[]]); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| var [x, ...[...y]] = [1, 2, 3]; | |
| }); | |
| assertEquals(log, []); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| let [x, ...[...y]] = [1, 2, 3]; | |
| }); | |
| assertEquals(log, []); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| const [x, ...[...y]] = [1, 2, 3]; | |
| }); | |
| assertEquals(log, []); | |
| log = []; | |
| assertDoesNotThrow(() => { | |
| (([x, ...[...y]]) => {})([1, 2, 3]); | |
| }); | |
| assertEquals(log, []); | |
| Array.prototype[Symbol.iterator] = backup; | |
| } | |
| } | |
| // Return method throws. | |
| { | |
| let log = []; | |
| g.prototype.return = (...args) => { log.push(args); throw 23 }; | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { break; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { break; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { break; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (x of g()) { break; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (x of g()) { throw 42; } | |
| }, 42); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) { return 42; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g()) { return 42; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (const x of g()) { return 42; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (x of g()) { return 42; } | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertEquals(42, eval('for (var x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, eval('for (let x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, eval('for (const x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertEquals(42, eval('for (x of g()) { x; }')); | |
| assertEquals([], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| var [x] = g(); return x; | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| let [x] = g(); return x; | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| const [x] = g(); return x; | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| [x] = g(); return x; | |
| }, 23); | |
| assertEquals([[]], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| (([x]) => x)(g()) | |
| }, 23); | |
| assertEquals([[]], log); | |
| } | |
| // Next method throws. | |
| { | |
| let closed = false; | |
| g.prototype.next = () => { throw 666; }; | |
| g.prototype.return = () => { closed = true; }; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (const x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| var [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| let [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| const [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| (([x]) => x)(g()); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| var [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| let [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| const [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| (([...x]) => x)(g()); | |
| }, 666); | |
| assertFalse(closed); | |
| } | |
| // Value throws. | |
| { | |
| let closed = false; | |
| g.prototype.next = () => ({get value() {throw 666}}); | |
| g.prototype.return = () => { closed = true; }; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (const x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| var [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| let [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| const [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| (([x]) => x)(g()); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| var [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| let [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| const [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| (([...x]) => x)(g()); | |
| }, 666); | |
| assertFalse(closed); | |
| } | |
| // Done throws. | |
| { | |
| let closed = false; | |
| g.prototype.next = () => ({get done() {throw 666}}); | |
| g.prototype.return = () => { closed = true; }; | |
| assertThrowsEquals(() => { | |
| for (var x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (const x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| for (x of g()) {} | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| var [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| let [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| const [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| [x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| (([x]) => x)(g()); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| var [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| let [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| const [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| [...x] = g(); | |
| }, 666); | |
| assertThrowsEquals(() => { | |
| (([...x]) => x)(g()); | |
| }, 666); | |
| assertFalse(closed); | |
| } | |
| // Nested loops. | |
| { | |
| function* g1() { yield 1; yield 2; throw 3; } | |
| function* g2() { yield -1; yield -2; throw -3; } | |
| assertDoesNotThrow(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) break; | |
| } | |
| if (x == 2) break; | |
| } | |
| }, -3); | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| } | |
| } | |
| }, -3); | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) break; | |
| } | |
| } | |
| }, 3); | |
| assertDoesNotThrow(() => { | |
| l: for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) break l; | |
| } | |
| } | |
| }); | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| throw 4; | |
| } | |
| } | |
| }, 4); | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) throw 4; | |
| } | |
| } | |
| }, 4); | |
| let log = []; | |
| g1.prototype.return = () => { log.push(1); throw 5 }; | |
| g2.prototype.return = () => { log.push(2); throw -5 }; | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) break; | |
| } | |
| if (x == 2) break; | |
| } | |
| }, -5); | |
| assertEquals([2, 1], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| } | |
| } | |
| }, -3); | |
| assertEquals([1], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) break; | |
| } | |
| } | |
| }, -5); | |
| assertEquals([2, 1], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| l: for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) break l; | |
| } | |
| } | |
| }, -5); | |
| assertEquals([2, 1], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| throw 4; | |
| } | |
| } | |
| }, 4); | |
| assertEquals([2, 1], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| for (let y of g2()) { | |
| if (y == -2) throw 4; | |
| } | |
| } | |
| }, 4); | |
| assertEquals([2, 1], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| try { | |
| for (let y of g2()) { | |
| } | |
| } catch (_) {} | |
| } | |
| }, 3); | |
| assertEquals([], log); | |
| log = []; | |
| assertThrowsEquals(() => { | |
| for (let x of g1()) { | |
| try { | |
| for (let y of g2()) { | |
| } | |
| } catch (_) {} | |
| if (x == 2) break; | |
| } | |
| }, 5); | |
| assertEquals([1], log); | |
| } | |
| // yield*, argument's return method is "undefined". | |
| function TestYieldStarWithoutReturn(get_iterable) { | |
| assertTrue(get_iterable().return == undefined); | |
| function* g() { yield* get_iterable() } | |
| { | |
| let gen = g(); | |
| assertEquals({value: 1, done: false}, gen.next()); | |
| assertEquals({value: undefined, done: true}, gen.return()); | |
| } | |
| assertEquals(42, (() => { | |
| for (let x of g()) break; | |
| return 42; | |
| })()); | |
| assertEquals(42, (() => { | |
| for (let x of g()) return 42; | |
| })()); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) throw 42; | |
| }, 42); | |
| } | |
| { | |
| let get_iterable1 = () => [1, 2]; | |
| let get_iterable2 = function*() { yield 1; yield 2 }; | |
| get_iterable2.prototype.return = null; | |
| TestYieldStarWithoutReturn(get_iterable1); | |
| TestYieldStarWithoutReturn(get_iterable2); | |
| } | |
| // yield*, argument's return method is defined. | |
| { | |
| let get_iterable = function*() { yield 1; yield 2 }; | |
| const obj = {}; | |
| get_iterable.prototype.return = (...args) => obj; | |
| function* g() { yield* get_iterable() } | |
| { | |
| let gen = g(); | |
| assertEquals({value: 1, done: false}, gen.next()); | |
| assertSame(obj, gen.return()); | |
| assertSame(obj, gen.return()); | |
| assertSame(obj, gen.return()); | |
| assertEquals({value: 2, done: false}, gen.next()); | |
| assertSame(obj, gen.return()); | |
| assertSame(obj, gen.return()); | |
| assertSame(obj, gen.return()); | |
| assertEquals({value: undefined, done: true}, gen.next()); | |
| assertEquals({value: undefined, done: true}, gen.return()); | |
| assertEquals({value: undefined, done: true}, gen.return()); | |
| } | |
| assertEquals(42, (() => { | |
| for (let x of g()) break; | |
| return 42; | |
| })()); | |
| assertEquals(42, (() => { | |
| for (let x of g()) return 42; | |
| })()); | |
| assertThrowsEquals(() => { | |
| for (let x of g()) throw 42; | |
| }, 42); | |
| } |