Commit ef8fa852 authored by neis's avatar neis Committed by Commit bot

Fix accidental bug in yield* desugaring.

The for-of-finalization CL incorrectly removed the input argument from
BuildIteratorClose.  I'm reverting this, adding a regression test, and fixing an
existing test that was wrong.

BUG=
R=rossberg

Review URL: https://codereview.chromium.org/1750543002

Cr-Commit-Position: refs/heads/master@{#34384}
parent c4f39389
...@@ -6049,9 +6049,8 @@ Expression* ParserTraits::RewriteYieldStar( ...@@ -6049,9 +6049,8 @@ Expression* ParserTraits::RewriteYieldStar(
Block* then = factory->NewBlock(nullptr, 4+1, false, nopos); Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
Variable* var_tmp = scope->NewTemporary(avfactory->empty_string()); Variable* var_tmp = scope->NewTemporary(avfactory->empty_string());
BuildIteratorClose( BuildIteratorClose(then->statements(), var_iterator, Nothing<Variable*>(),
then->statements(), var_iterator, factory->NewUndefinedLiteral(nopos), var_tmp);
var_tmp);
then->statements()->Add(throw_call, zone); then->statements()->Add(throw_call, zone);
check_throw = factory->NewIfStatement( check_throw = factory->NewIfStatement(
condition, then, factory->NewEmptyStatement(nopos), nopos); condition, then, factory->NewEmptyStatement(nopos), nopos);
...@@ -6226,8 +6225,7 @@ Expression* ParserTraits::RewriteYieldStar( ...@@ -6226,8 +6225,7 @@ Expression* ParserTraits::RewriteYieldStar(
case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone); case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
auto case_return = new (zone) ZoneList<Statement*>(5, zone); auto case_return = new (zone) ZoneList<Statement*>(5, zone);
BuildIteratorClose(case_return, var_iterator, BuildIteratorClose(case_return, var_iterator, Just(var_input), var_output);
factory->NewVariableProxy(var_input, nopos), var_output);
case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone); case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
auto case_throw = new (zone) ZoneList<Statement*>(5, zone); auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
...@@ -6472,17 +6470,21 @@ Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) { ...@@ -6472,17 +6470,21 @@ Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) {
void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
Variable* iterator, Variable* iterator,
Expression* input, Maybe<Variable*> input,
Variable* var_output) { Variable* var_output) {
// //
// This function adds four statements to [statements], corresponding to the // This function adds four statements to [statements], corresponding to the
// following code: // following code:
// //
// let iteratorReturn = iterator.return; // let iteratorReturn = iterator.return;
// if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input; // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return |input|;
// output = %_Call(iteratorReturn, iterator); // output = %_Call(iteratorReturn, iterator|, input|);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// //
// Here, |...| denotes optional parts, depending on the presence of the
// input variable. The reason for allowing input is that BuildIteratorClose
// can then be reused to handle the return case in yield*.
//
const int nopos = RelocInfo::kNoPosition; const int nopos = RelocInfo::kNoPosition;
auto factory = parser_->factory(); auto factory = parser_->factory();
...@@ -6504,25 +6506,33 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements, ...@@ -6504,25 +6506,33 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
get_return = factory->NewExpressionStatement(assignment, nopos); get_return = factory->NewExpressionStatement(assignment, nopos);
} }
// if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input; // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return |input|;
Statement* check_return; Statement* check_return;
{ {
Expression* condition = factory->NewCompareOperation( Expression* condition = factory->NewCompareOperation(
Token::EQ, factory->NewVariableProxy(var_return), Token::EQ, factory->NewVariableProxy(var_return),
factory->NewNullLiteral(nopos), nopos); factory->NewNullLiteral(nopos), nopos);
Statement* return_input = factory->NewReturnStatement(input, nopos); Expression* value = input.IsJust()
? static_cast<Expression*>(
factory->NewVariableProxy(input.FromJust()))
: factory->NewUndefinedLiteral(nopos);
Statement* return_input = factory->NewReturnStatement(value, nopos);
check_return = factory->NewIfStatement( check_return = factory->NewIfStatement(
condition, return_input, factory->NewEmptyStatement(nopos), nopos); condition, return_input, factory->NewEmptyStatement(nopos), nopos);
} }
// output = %_Call(iteratorReturn, iterator); // output = %_Call(iteratorReturn, iterator, |input|);
Statement* call_return; Statement* call_return;
{ {
auto args = new (zone) ZoneList<Expression*>(3, zone); auto args = new (zone) ZoneList<Expression*>(3, zone);
args->Add(factory->NewVariableProxy(var_return), zone); args->Add(factory->NewVariableProxy(var_return), zone);
args->Add(factory->NewVariableProxy(iterator), zone); args->Add(factory->NewVariableProxy(iterator), zone);
if (input.IsJust()) {
args->Add(factory->NewVariableProxy(input.FromJust()), zone);
}
Expression* call = Expression* call =
factory->NewCallRuntime(Runtime::kInlineCall, args, nopos); factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
......
...@@ -670,9 +670,8 @@ class ParserTraits { ...@@ -670,9 +670,8 @@ class ParserTraits {
private: private:
Parser* parser_; Parser* parser_;
void BuildIteratorClose( void BuildIteratorClose(ZoneList<Statement*>* statements, Variable* iterator,
ZoneList<Statement*>* statements, Variable* iterator, Maybe<Variable*> input, Variable* output);
Expression* input, Variable* output);
void BuildIteratorCloseForCompletion( void BuildIteratorCloseForCompletion(
ZoneList<Statement*>* statements, Variable* iterator, ZoneList<Statement*>* statements, Variable* iterator,
Variable* body_threw); Variable* body_threw);
......
...@@ -237,8 +237,8 @@ ...@@ -237,8 +237,8 @@
let x = g(); let x = g();
assertEquals({value: 1, done: false}, x.next()); assertEquals({value: 1, done: false}, x.next());
assertEquals({value: 42, done: false}, x.next()); assertEquals({value: 42, done: false}, x.next());
assertEquals({value: 43, done: false}, x.return(666)); assertEquals({value: 43, done: false}, x.return(44));
assertEquals({value: undefined, done: false}, x.next()); assertEquals({value: 44, done: false}, x.next());
assertEquals({value: undefined, done: true}, x.next()); assertEquals({value: undefined, done: true}, x.next());
} }
...@@ -250,3 +250,23 @@ ...@@ -250,3 +250,23 @@
assertThrowsEquals(() => x.next(), 666); assertThrowsEquals(() => x.next(), 666);
} }
} }
{ // yield*, .return argument is final result
function* inner() {
yield 2;
}
function* g() {
yield 1;
return yield* inner();
}
{
let x = g();
assertEquals({value: 1, done: false}, x.next());
assertEquals({value: 2, done: false}, x.next());
assertEquals({value: 42, done: true}, x.return(42));
}
}
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