Commit 6dffb078 authored by neis's avatar neis Committed by Commit bot

Fix behavior of return on yield*.

When calling the return method on a generator suspended inside a yield*, yield*
in turn calls return on its iterable.  If this results in a "done" iterator,
yield* must return immediately, thus terminating the generator.  For some
reason, we didn't terminate the generator but continued right after the yield*.

R=adamk@chromium.org
BUG=v8:5131

Review-Url: https://codereview.chromium.org/2100093002
Cr-Commit-Position: refs/heads/master@{#37310}
parent 610a8cbb
......@@ -6009,7 +6009,10 @@ void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
// }
// }
//
// output.value;
// if (mode === kReturn) {
// return {value: output.value, done: true};
// }
// output.value
// }
//
// IteratorClose(iterator) expands to the following:
......@@ -6305,7 +6308,30 @@ Expression* ParserTraits::RewriteYieldStar(
}
// output.value;
// if (mode === kReturn) {
// return {value: output.value, done: true};
// }
Statement* maybe_return_value;
{
Expression* mode_proxy = factory->NewVariableProxy(var_mode);
Expression* kreturn =
factory->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
Expression* condition = factory->NewCompareOperation(
Token::EQ_STRICT, mode_proxy, kreturn, nopos);
Expression* output_proxy = factory->NewVariableProxy(var_output);
Expression* literal =
factory->NewStringLiteral(avfactory->value_string(), nopos);
Expression* property = factory->NewProperty(output_proxy, literal, nopos);
Statement* return_value =
factory->NewReturnStatement(BuildIteratorResult(property, true), nopos);
maybe_return_value = factory->NewIfStatement(
condition, return_value, factory->NewEmptyStatement(nopos), nopos);
}
// output.value
Statement* get_value;
{
Expression* output_proxy = factory->NewVariableProxy(var_output);
......@@ -6408,13 +6434,14 @@ Expression* ParserTraits::RewriteYieldStar(
// The rewriter needs to process the get_value statement only, hence we
// put the preceding statements into an init block.
Block* do_block_ = factory->NewBlock(nullptr, 6, true, nopos);
Block* do_block_ = factory->NewBlock(nullptr, 7, true, nopos);
do_block_->statements()->Add(initialize_input, zone);
do_block_->statements()->Add(initialize_mode, zone);
do_block_->statements()->Add(initialize_output, zone);
do_block_->statements()->Add(get_iterator, zone);
do_block_->statements()->Add(validate_iterator, zone);
do_block_->statements()->Add(loop, zone);
do_block_->statements()->Add(maybe_return_value, zone);
Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
do_block->statements()->Add(do_block_, zone);
......
......@@ -49,7 +49,7 @@
try {
yield function.sent;
} finally {
return 666;
return 23;
}
}
......@@ -77,7 +77,7 @@
let x = g();
assertEquals({value: 1, done: false}, x.next(1));
assertEquals({value: undefined, done: false}, x.next(2));
assertEquals({value: 42, done: true}, x.return(42));
assertEquals({value: 23, done: true}, x.return(42));
}
}
......
......@@ -643,3 +643,13 @@ function Throw(generator, ...args) {
assertEquals({value: 42, done: false}, Next(g));
assertEquals({value: 42, done: false}, Next(g));
}
{
let foo = function*() {
yield* (function*() { yield 42; }());
assertUnreachable();
}
g = foo();
assertEquals({value: 42, done: false}, Next(g));
assertEquals({value: 23, done: true}, Return(g, 23));
}
......@@ -638,3 +638,13 @@ function Throw(generator, ...args) {
assertEquals({value: 42, done: false}, Next(g));
assertEquals({value: 42, done: false}, Next(g));
}
{
let foo = function*() {
yield* (function*() { yield 42; }());
assertUnreachable();
}
g = foo();
assertEquals({value: 42, done: false}, Next(g));
assertEquals({value: 23, done: true}, Return(g, 23));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment