2a0e4225dd
In a generator function, the parser rewrites a return statement into a "final" yield. A final yield used to close the generator, which was incorrect because the return may occur inside a try-finally clause and so the generator may not yet terminate. BUG= Review URL: https://codereview.chromium.org/1634553002 Cr-Commit-Position: refs/heads/master@{#33537}
95 lines
2.4 KiB
JavaScript
95 lines
2.4 KiB
JavaScript
// Copyright 2014 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.
|
|
|
|
// Test generator states.
|
|
|
|
function Foo() {}
|
|
function Bar() {}
|
|
|
|
function assertIteratorResult(value, done, result) {
|
|
assertEquals({ value: value, done: done}, result);
|
|
}
|
|
|
|
function assertIteratorIsClosed(iter) {
|
|
assertIteratorResult(undefined, true, iter.next());
|
|
// Next and throw on a closed iterator.
|
|
assertDoesNotThrow(function() { iter.next(); });
|
|
assertThrows(function() { iter.throw(new Bar); }, Bar);
|
|
}
|
|
|
|
var iter;
|
|
function* nextGenerator() { yield iter.next(); }
|
|
function* throwGenerator() { yield iter.throw(new Bar); }
|
|
|
|
// Throw on a suspendedStart iterator.
|
|
iter = nextGenerator();
|
|
assertThrows(function() { iter.throw(new Foo) }, Foo)
|
|
assertIteratorIsClosed(iter);
|
|
assertThrows(function() { iter.throw(new Foo) }, Foo)
|
|
assertIteratorIsClosed(iter);
|
|
|
|
// The same.
|
|
iter = throwGenerator();
|
|
assertThrows(function() { iter.throw(new Foo) }, Foo)
|
|
assertThrows(function() { iter.throw(new Foo) }, Foo)
|
|
assertIteratorIsClosed(iter);
|
|
|
|
// Next on an executing iterator raises a TypeError.
|
|
iter = nextGenerator();
|
|
assertThrows(function() { iter.next() }, TypeError)
|
|
assertIteratorIsClosed(iter);
|
|
|
|
// Throw on an executing iterator raises a TypeError.
|
|
iter = throwGenerator();
|
|
assertThrows(function() { iter.next() }, TypeError)
|
|
assertIteratorIsClosed(iter);
|
|
|
|
// Next on an executing iterator doesn't change the state of the
|
|
// generator.
|
|
iter = (function* () {
|
|
try {
|
|
iter.next();
|
|
yield 1;
|
|
} catch (e) {
|
|
try {
|
|
// This next() should raise the same exception, because the first
|
|
// next() left the iter in the executing state.
|
|
iter.next();
|
|
yield 2;
|
|
} catch (e) {
|
|
yield 3;
|
|
}
|
|
}
|
|
yield 4;
|
|
})();
|
|
assertIteratorResult(3, false, iter.next());
|
|
assertIteratorResult(4, false, iter.next());
|
|
assertIteratorIsClosed(iter);
|
|
|
|
|
|
// A return that doesn't close.
|
|
{
|
|
let g = function*() { try {return 42} finally {yield 43} };
|
|
|
|
let x = g();
|
|
assertEquals({value: 43, done: false}, x.next());
|
|
assertEquals({value: 42, done: true}, x.next());
|
|
}
|
|
{
|
|
let x;
|
|
let g = function*() { try {return 42} finally {x.throw(666)} };
|
|
|
|
x = g();
|
|
assertThrows(() => x.next(), TypeError); // Still executing.
|
|
}
|
|
{
|
|
let x;
|
|
let g = function*() {
|
|
try {return 42} finally {try {x.throw(666)} catch(e) {}}
|
|
};
|
|
|
|
x = g();
|
|
assertEquals({value: 42, done: true}, x.next());
|
|
}
|