[strong] Deprecate for-in
authorrossberg <rossberg@chromium.org>
Thu, 19 Feb 2015 13:50:33 +0000 (05:50 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 19 Feb 2015 13:50:41 +0000 (13:50 +0000)
R=marja@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#26751}

src/messages.js
src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
test/cctest/test-parsing.cc
test/mjsunit/strong/empty-statement.js
test/mjsunit/strong/for-in.js [new file with mode: 0644]

index 19d6104..510147f 100644 (file)
@@ -164,6 +164,7 @@ var kMessages = {
   strong_equal:                  ["Please don't use '==' or '!=' in strong mode, use '===' or '!==' instead"],
   strong_delete:                 ["Please don't use 'delete' in strong mode, use maps or sets instead"],
   strong_var:                    ["Please don't use 'var' in strong mode, use 'let' or 'const' instead"],
+  strong_for_in:                 ["Please don't use 'for'-'in' loops in strong mode, use 'for'-'of' instead"],
   strong_empty:                  ["Please don't use empty sub-statements in strong mode, make them explicit with '{}' instead"],
   sloppy_lexical:                ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
   malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"],
index bb8cb52..1fc131c 100644 (file)
@@ -2881,19 +2881,6 @@ WhileStatement* Parser::ParseWhileStatement(
 }
 
 
-bool Parser::CheckInOrOf(bool accept_OF,
-                         ForEachStatement::VisitMode* visit_mode) {
-  if (Check(Token::IN)) {
-    *visit_mode = ForEachStatement::ENUMERATE;
-    return true;
-  } else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
-    *visit_mode = ForEachStatement::ITERATE;
-    return true;
-  }
-  return false;
-}
-
-
 void Parser::InitializeForEachStatement(ForEachStatement* stmt,
                                         Expression* each,
                                         Expression* subject,
@@ -3222,7 +3209,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
       ForEachStatement::VisitMode mode;
       int each_pos = position();
 
-      if (name != NULL && CheckInOrOf(accept_OF, &mode)) {
+      if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) {
+        if (!*ok) return nullptr;
         ForEachStatement* loop =
             factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
@@ -3259,7 +3247,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
       ForEachStatement::VisitMode mode;
       int each_pos = position();
 
-      if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
+      if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
+        if (!*ok) return nullptr;
+
         // Rewrite a for-in statement of the form
         //
         //   for (let/const x in e) b
@@ -3321,7 +3311,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         expression->AsVariableProxy()->raw_name() ==
             ast_value_factory()->let_string();
 
-      if (CheckInOrOf(accept_OF, &mode)) {
+      if (CheckInOrOf(accept_OF, &mode, ok)) {
+        if (!*ok) return nullptr;
         expression = this->CheckAndRewriteReferenceExpression(
             expression, lhs_location, "invalid_lhs_in_for", CHECK_OK);
 
index ff36fe9..bdfe440 100644 (file)
@@ -781,8 +781,6 @@ class Parser : public ParserBase<ParserTraits> {
   // Magical syntax support.
   Expression* ParseV8Intrinsic(bool* ok);
 
-  bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
-
   // Get odd-ball literals.
   Literal* GetLiteralUndefined(int position);
 
index 00332ad..154a9ae 100644 (file)
@@ -715,15 +715,6 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
 }
 
 
-bool PreParser::CheckInOrOf(bool accept_OF) {
-  if (Check(Token::IN) ||
-      (accept_OF && CheckContextualKeyword(CStrVector("of")))) {
-    return true;
-  }
-  return false;
-}
-
-
 PreParser::Statement PreParser::ParseForStatement(bool* ok) {
   // ForStatement ::
   //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
@@ -732,6 +723,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
   Expect(Token::LPAREN, CHECK_OK);
   bool is_let_identifier_expression = false;
   if (peek() != Token::SEMICOLON) {
+    ForEachStatement::VisitMode visit_mode;
     if (peek() == Token::VAR || peek() == Token::CONST ||
         (peek() == Token::LET && is_strict(language_mode()))) {
       bool is_lexical = peek() == Token::LET ||
@@ -743,10 +735,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
       bool has_initializers = decl_props == kHasInitializers;
       bool accept_IN = decl_count == 1 && !(is_lexical && has_initializers);
       bool accept_OF = !has_initializers;
-      if (accept_IN && CheckInOrOf(accept_OF)) {
+      if (accept_IN && CheckInOrOf(accept_OF, &visit_mode, ok)) {
+        if (!*ok) return Statement::Default();
         ParseExpression(true, CHECK_OK);
         Expect(Token::RPAREN, CHECK_OK);
-
         ParseSubStatement(CHECK_OK);
         return Statement::Default();
       }
@@ -754,10 +746,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
       Expression lhs = ParseExpression(false, CHECK_OK);
       is_let_identifier_expression =
           lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
-      if (CheckInOrOf(lhs.IsIdentifier())) {
+      if (CheckInOrOf(lhs.IsIdentifier(), &visit_mode, ok)) {
+        if (!*ok) return Statement::Default();
         ParseExpression(true, CHECK_OK);
         Expect(Token::RPAREN, CHECK_OK);
-
         ParseSubStatement(CHECK_OK);
         return Statement::Default();
       }
index 1cd5dad..0f9cb46 100644 (file)
@@ -420,6 +420,23 @@ class ParserBase : public Traits {
     }
   }
 
+  bool CheckInOrOf(
+      bool accept_OF, ForEachStatement::VisitMode* visit_mode, bool* ok) {
+    if (Check(Token::IN)) {
+      if (is_strong(language_mode())) {
+        ReportMessageAt(scanner()->location(), "strong_for_in");
+        *ok = false;
+      } else {
+        *visit_mode = ForEachStatement::ENUMERATE;
+      }
+      return true;
+    } else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
+      *visit_mode = ForEachStatement::ITERATE;
+      return true;
+    }
+    return false;
+  }
+
   // Checks whether an octal literal was last seen between beg_pos and end_pos.
   // If so, reports an error. Only called for strict mode and template strings.
   void CheckOctalLiteral(int beg_pos, int end_pos, const char* error,
@@ -1613,8 +1630,6 @@ class PreParser : public ParserBase<PreParserTraits> {
                                         Scanner::Location class_name_location,
                                         bool name_is_strict_reserved, int pos,
                                         bool* ok);
-
-  bool CheckInOrOf(bool accept_OF);
 };
 
 
index b6c427f..1a17475 100644 (file)
@@ -5548,3 +5548,25 @@ TEST(StrongEmptySubStatements) {
   RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
                     arraysize(always_flags));
 }
+
+
+TEST(StrongForIn) {
+  const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
+  const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
+  const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
+
+  const char* data[] = {
+      "for (x in []) {}",
+      "for (const x in []) {}",
+      NULL};
+
+  static const ParserFlag always_flags[] = {
+      kAllowStrongMode, kAllowHarmonyScoping
+  };
+  RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
index b63fead..65edf74 100644 (file)
@@ -15,5 +15,4 @@
   assertThrows("'use strong'; for (let x;;);", SyntaxError);
   assertThrows("'use strong'; for (let x in []);", SyntaxError);
   assertThrows("'use strong'; for (let x of []);", SyntaxError);
-  assertThrows("'use strong'; with ({});", SyntaxError);
 })();
diff --git a/test/mjsunit/strong/for-in.js b/test/mjsunit/strong/for-in.js
new file mode 100644 (file)
index 0000000..8fa9010
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+// Flags: --strong-mode
+
+(function NoForInStatement() {
+  assertThrows("'use strong'; for (x in []) {}", SyntaxError);
+  assertThrows("'use strong'; for (let x in []) {}", SyntaxError);
+  assertThrows("'use strong'; for (const x in []) {}", SyntaxError);
+})();
+
+(function ForOfStatement() {
+  assertTrue(eval("'use strong'; for (x of []) {} true"));
+  assertTrue(eval("'use strong'; for (let x of []) {} true"));
+  assertTrue(eval("'use strong'; for (const x of []) {} true"));
+})();