Commit 096125de authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

[es6] allow any LeftHandSideExpression in for-of loops

Fix an earlier regression which forbid non-VariableProxy LHS from being
used in for-of loops. Like for-in loops, the spec allows any LHS to be used,
with the sole exception that ObjectLiterals and ArrayLiterals must be valid
AssignmentPatterns.

Also fixes a bug in TurboFan which resulted in incorrectly replacing a variable load with a constant value in some instances, due to the AstLoopAssignmentAnalyzer failing to record the assignment to ForOfStatement's value.

BUG=v8:4418, v8:2720
LOG=N
R=wingo@igalia.com, littledan@chromium.org, adamk@chromium.org, bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#31816}
parent 8c1a4330
...@@ -261,7 +261,9 @@ void ALAA::VisitForInStatement(ForInStatement* loop) { ...@@ -261,7 +261,9 @@ void ALAA::VisitForInStatement(ForInStatement* loop) {
void ALAA::VisitForOfStatement(ForOfStatement* loop) { void ALAA::VisitForOfStatement(ForOfStatement* loop) {
Visit(loop->assign_iterator());
Enter(loop); Enter(loop);
Visit(loop->assign_each());
Visit(loop->each()); Visit(loop->each());
Visit(loop->subject()); Visit(loop->subject());
Visit(loop->body()); Visit(loop->body());
......
...@@ -3635,12 +3635,11 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3635,12 +3635,11 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
int num_decl = parsing_result.declarations.length(); int num_decl = parsing_result.declarations.length();
bool accept_IN = num_decl >= 1; bool accept_IN = num_decl >= 1;
bool accept_OF = true;
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
int each_beg_pos = scanner()->location().beg_pos; int each_beg_pos = scanner()->location().beg_pos;
int each_end_pos = scanner()->location().end_pos; int each_end_pos = scanner()->location().end_pos;
if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { if (accept_IN && CheckInOrOf(&mode, ok)) {
if (!*ok) return nullptr; if (!*ok) return nullptr;
if (num_decl != 1) { if (num_decl != 1) {
const char* loop_type = const char* loop_type =
...@@ -3798,13 +3797,12 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3798,13 +3797,12 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expression* expression = ParseExpression(false, CHECK_OK); Expression* expression = ParseExpression(false, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos; int lhs_end_pos = scanner()->location().end_pos;
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
bool accept_OF = expression->IsVariableProxy();
is_let_identifier_expression = is_let_identifier_expression =
expression->IsVariableProxy() && expression->IsVariableProxy() &&
expression->AsVariableProxy()->raw_name() == expression->AsVariableProxy()->raw_name() ==
ast_value_factory()->let_string(); ast_value_factory()->let_string();
if (CheckInOrOf(accept_OF, &mode, ok)) { if (CheckInOrOf(&mode, ok)) {
if (!*ok) return nullptr; if (!*ok) return nullptr;
expression = this->CheckAndRewriteReferenceExpression( expression = this->CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, lhs_end_pos, expression, lhs_beg_pos, lhs_end_pos,
......
...@@ -925,8 +925,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -925,8 +925,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
&first_initializer_loc, &bindings_loc, &first_initializer_loc, &bindings_loc,
CHECK_OK); CHECK_OK);
bool accept_IN = decl_count >= 1; bool accept_IN = decl_count >= 1;
bool accept_OF = true; if (accept_IN && CheckInOrOf(&mode, ok)) {
if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return Statement::Default(); if (!*ok) return Statement::Default();
if (decl_count != 1) { if (decl_count != 1) {
const char* loop_type = const char* loop_type =
...@@ -961,7 +960,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -961,7 +960,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
int lhs_end_pos = scanner()->location().end_pos; int lhs_end_pos = scanner()->location().end_pos;
is_let_identifier_expression = is_let_identifier_expression =
lhs.IsIdentifier() && lhs.AsIdentifier().IsLet(); lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
if (CheckInOrOf(lhs.IsIdentifier(), &mode, ok)) { if (CheckInOrOf(&mode, ok)) {
if (!*ok) return Statement::Default(); if (!*ok) return Statement::Default();
lhs = CheckAndRewriteReferenceExpression( lhs = CheckAndRewriteReferenceExpression(
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
......
...@@ -421,8 +421,7 @@ class ParserBase : public Traits { ...@@ -421,8 +421,7 @@ class ParserBase : public Traits {
} }
} }
bool CheckInOrOf( bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode, bool* ok) {
bool accept_OF, ForEachStatement::VisitMode* visit_mode, bool* ok) {
if (Check(Token::IN)) { if (Check(Token::IN)) {
if (is_strong(language_mode())) { if (is_strong(language_mode())) {
ReportMessageAt(scanner()->location(), MessageTemplate::kStrongForIn); ReportMessageAt(scanner()->location(), MessageTemplate::kStrongForIn);
...@@ -431,7 +430,7 @@ class ParserBase : public Traits { ...@@ -431,7 +430,7 @@ class ParserBase : public Traits {
*visit_mode = ForEachStatement::ENUMERATE; *visit_mode = ForEachStatement::ENUMERATE;
} }
return true; return true;
} else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) { } else if (CheckContextualKeyword(CStrVector("of"))) {
*visit_mode = ForEachStatement::ITERATE; *visit_mode = ForEachStatement::ITERATE;
return true; return true;
} }
......
// Copyright 2015 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 TestForOfName() {
var result = 0;
var index;
for (index of [1, 2, 3, 4, 5]) result += index;
assertEquals(result, 15);
assertEquals(index, 5);
})();
(function TestForOfProperty() {
var O = {};
var result = 0;
for (O.index of [1, 2, 3, 4, 5]) result += O.index;
assertEquals(result, 15);
assertEquals(O.index, 5);
})();
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