Commit d5dcce33 authored by nikolaos's avatar nikolaos Committed by Commit bot

[parser] Fix tail calls in for in/of loops

According to the ES6 specification, in "for in/of" loops like:

   for (var v of [1,2,3]) return f(...);

the call to f() should not be considered a tail call.  This was
not working properly, i.e., the case without declarations:

   var v;
   for (v of [1,2,3]) return f(...);

R=adamk@chromium.org, ishell@chromium.org
BUG=
LOG=N

Review-Url: https://codereview.chromium.org/2343823002
Cr-Commit-Position: refs/heads/master@{#39497}
parent cb13d50a
......@@ -2609,17 +2609,27 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::RPAREN, CHECK_OK);
// For legacy compat reasons, give for loops similar treatment to
// if statements in allowing a function declaration for a body
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
Statement* final_loop = InitializeForEachStatement(
loop, expression, enumerable, body, each_keyword_position);
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(&scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
Scope* for_scope = for_state.FinalizedBlockScope();
DCHECK_NULL(for_scope);
USE(for_scope);
return final_loop;
// For legacy compat reasons, give for loops similar treatment to
// if statements in allowing a function declaration for a body
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
block_state.set_end_position(scanner()->location().end_pos);
Statement* final_loop = InitializeForEachStatement(
loop, expression, enumerable, body, each_keyword_position);
Scope* for_scope = for_state.FinalizedBlockScope();
DCHECK_NULL(for_scope);
USE(for_scope);
Scope* block_scope = block_state.FinalizedBlockScope();
DCHECK_NULL(block_scope);
USE(block_scope);
return final_loop;
}
} else {
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
......
......@@ -295,7 +295,7 @@ function f_153(expected_call_stack, a) {
function test() {
var o = new A();
%DebugPrint(o);
//%DebugPrint(o);
assertEquals(153, o.x);
}
......@@ -387,18 +387,57 @@ function f_153(expected_call_stack, a) {
}
}
function g1let() {
for (let v in {a:0}) {
return f_153([f_153, g1let, test]);
}
}
function g1nodecl() {
var v;
for (v in {a:0}) {
return f_153([f_153, g1nodecl, test]);
}
}
function g2() {
for (var v of [1, 2, 3]) {
return f_153([f_153, g2, test]);
}
}
function g2let() {
for (let v of [1, 2, 3]) {
return f_153([f_153, g2let, test]);
}
}
function g2nodecl() {
var v;
for (v of [1, 2, 3]) {
return f_153([f_153, g2nodecl, test]);
}
}
function g3() {
for (var i = 0; i < 10; i++) {
return f_153([f_153, test]);
}
}
function g3let() {
for (let i = 0; i < 10; i++) {
return f_153([f_153, test]);
}
}
function g3nodecl() {
var i;
for (i = 0; i < 10; i++) {
return f_153([f_153, test]);
}
}
function g4() {
while (true) {
return f_153([f_153, test]);
......@@ -413,8 +452,14 @@ function f_153(expected_call_stack, a) {
function test() {
assertEquals(153, g1());
assertEquals(153, g1let());
assertEquals(153, g1nodecl());
assertEquals(153, g2());
assertEquals(153, g2let());
assertEquals(153, g2nodecl());
assertEquals(153, g3());
assertEquals(153, g3let());
assertEquals(153, g3nodecl());
assertEquals(153, g4());
assertEquals(153, g5());
}
......
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