| Index: src/parsing/parser-base.h | 
| diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h | 
| index eade9a7402a4b7200e286d8b1f9067bbe6a88e5e..7db2d4a7f44a08315332472fd467c269b4ee3077 100644 | 
| --- a/src/parsing/parser-base.h | 
| +++ b/src/parsing/parser-base.h | 
| @@ -1302,6 +1302,20 @@ class ParserBase { | 
| bool* ok); | 
| StatementT ParseTryStatement(bool* ok); | 
| StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok); | 
| +  StatementT ParseForEachStatementWithDeclarations( | 
| +      int stmt_pos, ForInfo* for_info, BlockState* for_state, | 
| +      ZoneList<const AstRawString*>* labels, bool* ok); | 
| +  StatementT ParseForEachStatementWithoutDeclarations( | 
| +      int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, | 
| +      ForInfo* for_info, BlockState* for_state, | 
| +      ZoneList<const AstRawString*>* labels, bool* ok); | 
| + | 
| +  // Parse a C-style for loop: 'for (<init>; <cond>; <step>) { ... }' | 
| +  StatementT ParseStandardForLoop(int stmt_pos, StatementT init, | 
| +                                  bool bound_names_are_lexical, | 
| +                                  ForInfo* for_info, BlockState* for_state, | 
| +                                  ZoneList<const AstRawString*>* labels, | 
| +                                  bool* ok); | 
|  | 
| bool IsNextLetKeyword(); | 
| bool IsTrivialExpression(); | 
| @@ -5380,173 +5394,193 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( | 
| for_state.set_is_hidden(); | 
|  | 
| StatementT init = impl()->NullStatement(); | 
| -  if (peek() != Token::SEMICOLON) { | 
| -    // An initializer is present. | 
| -    if (peek() == Token::VAR || peek() == Token::CONST || | 
| -        (peek() == Token::LET && IsNextLetKeyword())) { | 
| -      // The initializer contains declarations. | 
| -      ParseVariableDeclarations(kForStatement, &for_info.parsing_result, | 
| -                                nullptr, CHECK_OK); | 
| -      bound_names_are_lexical = | 
| -          IsLexicalVariableMode(for_info.parsing_result.descriptor.mode); | 
| -      for_info.position = scanner()->location().beg_pos; | 
| - | 
| -      if (CheckInOrOf(&for_info.mode)) { | 
| -        // Just one declaration followed by in/of. | 
| -        if (for_info.parsing_result.declarations.length() != 1) { | 
| -          impl()->ReportMessageAt( | 
| -              for_info.parsing_result.bindings_loc, | 
| -              MessageTemplate::kForInOfLoopMultiBindings, | 
| -              ForEachStatement::VisitModeString(for_info.mode)); | 
| -          *ok = false; | 
| -          return impl()->NullStatement(); | 
| -        } | 
| -        if (for_info.parsing_result.first_initializer_loc.IsValid() && | 
| -            (is_strict(language_mode()) || | 
| -             for_info.mode == ForEachStatement::ITERATE || | 
| -             bound_names_are_lexical || | 
| -             !impl()->IsIdentifier( | 
| -                 for_info.parsing_result.declarations[0].pattern))) { | 
| -          impl()->ReportMessageAt( | 
| -              for_info.parsing_result.first_initializer_loc, | 
| -              MessageTemplate::kForInOfLoopInitializer, | 
| -              ForEachStatement::VisitModeString(for_info.mode)); | 
| -          *ok = false; | 
| -          return impl()->NullStatement(); | 
| -        } | 
|  | 
| -        BlockT init_block = impl()->RewriteForVarInLegacy(for_info); | 
| +  if (peek() == Token::VAR || peek() == Token::CONST || | 
| +      (peek() == Token::LET && IsNextLetKeyword())) { | 
| +    // The initializer contains declarations. | 
| +    ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr, | 
| +                              CHECK_OK); | 
| +    bound_names_are_lexical = | 
| +        IsLexicalVariableMode(for_info.parsing_result.descriptor.mode); | 
| +    for_info.position = scanner()->location().beg_pos; | 
| + | 
| +    if (CheckInOrOf(&for_info.mode)) { | 
| +      return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, | 
| +                                                   &for_state, labels, ok); | 
| +    } | 
| + | 
| +    // One or more declaration not followed by in/of. | 
| +    init = impl()->BuildInitializationBlock( | 
| +        &for_info.parsing_result, | 
| +        bound_names_are_lexical ? &for_info.bound_names : nullptr, CHECK_OK); | 
| +  } else if (peek() != Token::SEMICOLON) { | 
| +    // The initializer does not contain declarations. | 
| +    int lhs_beg_pos = peek_position(); | 
| +    ExpressionClassifier classifier(this); | 
| +    ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK); | 
| +    int lhs_end_pos = scanner()->location().end_pos; | 
| + | 
| +    bool is_for_each = CheckInOrOf(&for_info.mode); | 
| +    bool is_destructuring = is_for_each && (expression->IsArrayLiteral() || | 
| +                                            expression->IsObjectLiteral()); | 
| + | 
| +    if (is_destructuring) { | 
| +      ValidateAssignmentPattern(CHECK_OK); | 
| +    } else { | 
| +      impl()->RewriteNonPattern(CHECK_OK); | 
| +    } | 
|  | 
| -        auto loop = | 
| -            factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); | 
| -        typename Types::Target target(this, loop); | 
| +    if (is_for_each) { | 
| +      return ParseForEachStatementWithoutDeclarations( | 
| +          stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, &for_state, | 
| +          labels, ok); | 
| +    } | 
| +    // Initializer is just an expression. | 
| +    init = factory()->NewExpressionStatement(expression, lhs_beg_pos); | 
| +  } | 
|  | 
| -        int each_keyword_pos = scanner()->location().beg_pos; | 
| +  // Standard 'for' loop, we have parsed the initializer at this point. | 
| +  return ParseStandardForLoop(stmt_pos, init, bound_names_are_lexical, | 
| +                              &for_info, &for_state, labels, ok); | 
| +} | 
|  | 
| -        ExpressionT enumerable = impl()->EmptyExpression(); | 
| -        if (for_info.mode == ForEachStatement::ITERATE) { | 
| -          ExpressionClassifier classifier(this); | 
| -          enumerable = ParseAssignmentExpression(true, CHECK_OK); | 
| -          impl()->RewriteNonPattern(CHECK_OK); | 
| -        } else { | 
| -          enumerable = ParseExpression(true, CHECK_OK); | 
| -        } | 
| +template <typename Impl> | 
| +typename ParserBase<Impl>::StatementT | 
| +ParserBase<Impl>::ParseForEachStatementWithDeclarations( | 
| +    int stmt_pos, ForInfo* for_info, BlockState* for_state, | 
| +    ZoneList<const AstRawString*>* labels, bool* ok) { | 
| +  // Just one declaration followed by in/of. | 
| +  if (for_info->parsing_result.declarations.length() != 1) { | 
| +    impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, | 
| +                            MessageTemplate::kForInOfLoopMultiBindings, | 
| +                            ForEachStatement::VisitModeString(for_info->mode)); | 
| +    *ok = false; | 
| +    return impl()->NullStatement(); | 
| +  } | 
| +  if (for_info->parsing_result.first_initializer_loc.IsValid() && | 
| +      (is_strict(language_mode()) || | 
| +       for_info->mode == ForEachStatement::ITERATE || | 
| +       IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) || | 
| +       !impl()->IsIdentifier( | 
| +           for_info->parsing_result.declarations[0].pattern))) { | 
| +    impl()->ReportMessageAt(for_info->parsing_result.first_initializer_loc, | 
| +                            MessageTemplate::kForInOfLoopInitializer, | 
| +                            ForEachStatement::VisitModeString(for_info->mode)); | 
| +    *ok = false; | 
| +    return impl()->NullStatement(); | 
| +  } | 
|  | 
| -        Expect(Token::RPAREN, CHECK_OK); | 
| +  BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); | 
|  | 
| -        StatementT final_loop = impl()->NullStatement(); | 
| -        { | 
| -          ReturnExprScope no_tail_calls(function_state_, | 
| -                                        ReturnExprContext::kInsideForInOfBody); | 
| -          BlockState block_state(zone(), &scope_state_); | 
| -          block_state.set_start_position(scanner()->location().beg_pos); | 
| - | 
| -          StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); | 
| - | 
| -          BlockT body_block = impl()->NullBlock(); | 
| -          ExpressionT each_variable = impl()->EmptyExpression(); | 
| -          impl()->DesugarBindingInForEachStatement(&for_info, &body_block, | 
| -                                                   &each_variable, CHECK_OK); | 
| -          body_block->statements()->Add(body, zone()); | 
| -          final_loop = impl()->InitializeForEachStatement( | 
| -              loop, each_variable, enumerable, body_block, each_keyword_pos); | 
| - | 
| -          block_state.set_end_position(scanner()->location().end_pos); | 
| -          body_block->set_scope(block_state.FinalizedBlockScope()); | 
| -        } | 
| +  auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); | 
| +  typename Types::Target target(this, loop); | 
|  | 
| -        init_block = | 
| -            impl()->CreateForEachStatementTDZ(init_block, for_info, ok); | 
| +  int each_keyword_pos = scanner()->location().beg_pos; | 
|  | 
| -        for_state.set_end_position(scanner()->location().end_pos); | 
| -        Scope* for_scope = for_state.FinalizedBlockScope(); | 
| -        // Parsed for-in loop w/ variable declarations. | 
| -        if (!impl()->IsNullStatement(init_block)) { | 
| -          init_block->statements()->Add(final_loop, zone()); | 
| -          init_block->set_scope(for_scope); | 
| -          return init_block; | 
| -        } else { | 
| -          DCHECK_NULL(for_scope); | 
| -          return final_loop; | 
| -        } | 
| -      } else { | 
| -        // One or more declaration not followed by in/of. | 
| -        init = impl()->BuildInitializationBlock( | 
| -            &for_info.parsing_result, | 
| -            bound_names_are_lexical ? &for_info.bound_names : nullptr, | 
| -            CHECK_OK); | 
| -      } | 
| -    } else { | 
| -      // The initializer does not contain declarations. | 
| -      int lhs_beg_pos = peek_position(); | 
| -      ExpressionClassifier classifier(this); | 
| -      ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK); | 
| -      int lhs_end_pos = scanner()->location().end_pos; | 
| +  ExpressionT enumerable = impl()->EmptyExpression(); | 
| +  if (for_info->mode == ForEachStatement::ITERATE) { | 
| +    ExpressionClassifier classifier(this); | 
| +    enumerable = ParseAssignmentExpression(true, CHECK_OK); | 
| +    impl()->RewriteNonPattern(CHECK_OK); | 
| +  } else { | 
| +    enumerable = ParseExpression(true, CHECK_OK); | 
| +  } | 
|  | 
| -      bool is_for_each = CheckInOrOf(&for_info.mode); | 
| -      bool is_destructuring = is_for_each && (expression->IsArrayLiteral() || | 
| -                                              expression->IsObjectLiteral()); | 
| +  Expect(Token::RPAREN, CHECK_OK); | 
|  | 
| -      if (is_destructuring) { | 
| -        ValidateAssignmentPattern(CHECK_OK); | 
| -      } else { | 
| -        impl()->RewriteNonPattern(CHECK_OK); | 
| -      } | 
| +  StatementT final_loop = impl()->NullStatement(); | 
| +  { | 
| +    ReturnExprScope no_tail_calls(function_state_, | 
| +                                  ReturnExprContext::kInsideForInOfBody); | 
| +    BlockState block_state(zone(), &scope_state_); | 
| +    block_state.set_start_position(scanner()->location().beg_pos); | 
|  | 
| -      if (is_for_each) { | 
| -        // Initializer is reference followed by in/of. | 
| -        if (!is_destructuring) { | 
| -          expression = impl()->CheckAndRewriteReferenceExpression( | 
| -              expression, lhs_beg_pos, lhs_end_pos, | 
| -              MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); | 
| -        } | 
| +    StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); | 
|  | 
| -        auto loop = | 
| -            factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); | 
| -        typename Types::Target target(this, loop); | 
| +    BlockT body_block = impl()->NullBlock(); | 
| +    ExpressionT each_variable = impl()->EmptyExpression(); | 
| +    impl()->DesugarBindingInForEachStatement(for_info, &body_block, | 
| +                                             &each_variable, CHECK_OK); | 
| +    body_block->statements()->Add(body, zone()); | 
| +    final_loop = impl()->InitializeForEachStatement( | 
| +        loop, each_variable, enumerable, body_block, each_keyword_pos); | 
|  | 
| -        int each_keyword_pos = scanner()->location().beg_pos; | 
| +    block_state.set_end_position(scanner()->location().end_pos); | 
| +    body_block->set_scope(block_state.FinalizedBlockScope()); | 
| +  } | 
|  | 
| -        ExpressionT enumerable = impl()->EmptyExpression(); | 
| -        if (for_info.mode == ForEachStatement::ITERATE) { | 
| -          ExpressionClassifier classifier(this); | 
| -          enumerable = ParseAssignmentExpression(true, CHECK_OK); | 
| -          impl()->RewriteNonPattern(CHECK_OK); | 
| -        } else { | 
| -          enumerable = ParseExpression(true, CHECK_OK); | 
| -        } | 
| +  init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok); | 
|  | 
| -        Expect(Token::RPAREN, CHECK_OK); | 
| +  for_state->set_end_position(scanner()->location().end_pos); | 
| +  Scope* for_scope = for_state->FinalizedBlockScope(); | 
| +  // Parsed for-in loop w/ variable declarations. | 
| +  if (!impl()->IsNullStatement(init_block)) { | 
| +    init_block->statements()->Add(final_loop, zone()); | 
| +    init_block->set_scope(for_scope); | 
| +    return init_block; | 
| +  } | 
|  | 
| -        { | 
| -          ReturnExprScope no_tail_calls(function_state_, | 
| -                                        ReturnExprContext::kInsideForInOfBody); | 
| -          BlockState block_state(zone(), &scope_state_); | 
| -          block_state.set_start_position(scanner()->location().beg_pos); | 
| - | 
| -          // For legacy compat reasons, give for loops similar treatment to | 
| -          // if statements in allowing a function declaration for a body | 
| -          StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); | 
| -          block_state.set_end_position(scanner()->location().end_pos); | 
| -          StatementT final_loop = impl()->InitializeForEachStatement( | 
| -              loop, expression, enumerable, body, each_keyword_pos); | 
| - | 
| -          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 { | 
| -        // Initializer is just an expression. | 
| -        init = factory()->NewExpressionStatement(expression, lhs_beg_pos); | 
| -      } | 
| -    } | 
| +  DCHECK_NULL(for_scope); | 
| +  return final_loop; | 
| +} | 
| + | 
| +template <typename Impl> | 
| +typename ParserBase<Impl>::StatementT | 
| +ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( | 
| +    int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, | 
| +    ForInfo* for_info, BlockState* for_state, | 
| +    ZoneList<const AstRawString*>* labels, bool* ok) { | 
| +  // Initializer is reference followed by in/of. | 
| +  if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { | 
| +    expression = impl()->CheckAndRewriteReferenceExpression( | 
| +        expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, | 
| +        kSyntaxError, CHECK_OK); | 
| } | 
|  | 
| -  // Standard 'for' loop, we have parsed the initializer at this point. | 
| +  auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); | 
| +  typename Types::Target target(this, loop); | 
| + | 
| +  int each_keyword_pos = scanner()->location().beg_pos; | 
| + | 
| +  ExpressionT enumerable = impl()->EmptyExpression(); | 
| +  if (for_info->mode == ForEachStatement::ITERATE) { | 
| +    ExpressionClassifier classifier(this); | 
| +    enumerable = ParseAssignmentExpression(true, CHECK_OK); | 
| +    impl()->RewriteNonPattern(CHECK_OK); | 
| +  } else { | 
| +    enumerable = ParseExpression(true, CHECK_OK); | 
| +  } | 
| + | 
| +  Expect(Token::RPAREN, CHECK_OK); | 
| + | 
| +  { | 
| +    ReturnExprScope no_tail_calls(function_state_, | 
| +                                  ReturnExprContext::kInsideForInOfBody); | 
| +    BlockState block_state(zone(), &scope_state_); | 
| +    block_state.set_start_position(scanner()->location().beg_pos); | 
| + | 
| +    // For legacy compat reasons, give for loops similar treatment to | 
| +    // if statements in allowing a function declaration for a body | 
| +    StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); | 
| +    block_state.set_end_position(scanner()->location().end_pos); | 
| +    StatementT final_loop = impl()->InitializeForEachStatement( | 
| +        loop, expression, enumerable, body, each_keyword_pos); | 
| + | 
| +    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; | 
| +  } | 
| +} | 
| + | 
| +template <typename Impl> | 
| +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( | 
| +    int stmt_pos, StatementT init, bool bound_names_are_lexical, | 
| +    ForInfo* for_info, BlockState* for_state, | 
| +    ZoneList<const AstRawString*>* labels, bool* ok) { | 
| auto loop = factory()->NewForStatement(labels, stmt_pos); | 
| typename Types::Target target(this, loop); | 
|  | 
| @@ -5560,7 +5594,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( | 
| // for loop must be parsed in a new scope. | 
| Scope* inner_scope = scope(); | 
| // TODO(verwaest): Allocate this through a ScopeState as well. | 
| -  if (bound_names_are_lexical && for_info.bound_names.length() > 0) { | 
| +  if (bound_names_are_lexical && for_info->bound_names.length() > 0) { | 
| inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE); | 
| inner_scope->set_start_position(scanner()->location().beg_pos); | 
| } | 
| @@ -5581,46 +5615,46 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( | 
| body = ParseScopedStatement(nullptr, true, CHECK_OK); | 
| } | 
|  | 
| -  if (bound_names_are_lexical && for_info.bound_names.length() > 0) { | 
| +  if (bound_names_are_lexical && for_info->bound_names.length() > 0) { | 
| auto result = impl()->DesugarLexicalBindingsInForStatement( | 
| -        loop, init, cond, next, body, inner_scope, for_info, CHECK_OK); | 
| -    for_state.set_end_position(scanner()->location().end_pos); | 
| +        loop, init, cond, next, body, inner_scope, *for_info, CHECK_OK); | 
| +    for_state->set_end_position(scanner()->location().end_pos); | 
| return result; | 
| -  } else { | 
| -    for_state.set_end_position(scanner()->location().end_pos); | 
| -    Scope* for_scope = for_state.FinalizedBlockScope(); | 
| -    if (for_scope != nullptr) { | 
| -      // Rewrite a for statement of the form | 
| -      //   for (const x = i; c; n) b | 
| -      // | 
| -      // into | 
| -      // | 
| -      //   { | 
| -      //     const x = i; | 
| -      //     for (; c; n) b | 
| -      //   } | 
| -      // | 
| -      // or, desugar | 
| -      //   for (; c; n) b | 
| -      // into | 
| -      //   { | 
| -      //     for (; c; n) b | 
| -      //   } | 
| -      // just in case b introduces a lexical binding some other way, e.g., if b | 
| -      // is a FunctionDeclaration. | 
| -      BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition); | 
| -      if (!impl()->IsNullStatement(init)) { | 
| -        block->statements()->Add(init, zone()); | 
| -      } | 
| -      block->statements()->Add(loop, zone()); | 
| -      block->set_scope(for_scope); | 
| -      loop->Initialize(init, cond, next, body); | 
| -      return block; | 
| -    } else { | 
| -      loop->Initialize(init, cond, next, body); | 
| -      return loop; | 
| -    } | 
| } | 
| + | 
| +  for_state->set_end_position(scanner()->location().end_pos); | 
| +  Scope* for_scope = for_state->FinalizedBlockScope(); | 
| +  if (for_scope != nullptr) { | 
| +    // Rewrite a for statement of the form | 
| +    //   for (const x = i; c; n) b | 
| +    // | 
| +    // into | 
| +    // | 
| +    //   { | 
| +    //     const x = i; | 
| +    //     for (; c; n) b | 
| +    //   } | 
| +    // | 
| +    // or, desugar | 
| +    //   for (; c; n) b | 
| +    // into | 
| +    //   { | 
| +    //     for (; c; n) b | 
| +    //   } | 
| +    // just in case b introduces a lexical binding some other way, e.g., if b | 
| +    // is a FunctionDeclaration. | 
| +    BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition); | 
| +    if (!impl()->IsNullStatement(init)) { | 
| +      block->statements()->Add(init, zone()); | 
| +    } | 
| +    block->statements()->Add(loop, zone()); | 
| +    block->set_scope(for_scope); | 
| +    loop->Initialize(init, cond, next, body); | 
| +    return block; | 
| +  } | 
| + | 
| +  loop->Initialize(init, cond, next, body); | 
| +  return loop; | 
| } | 
|  | 
| #undef CHECK_OK | 
|  |