Revert of [strong] checking of this & super in constructors (patchset #7 id:110001...
authormachenbach <machenbach@chromium.org>
Wed, 22 Apr 2015 08:00:39 +0000 (01:00 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 22 Apr 2015 08:00:27 +0000 (08:00 +0000)
Reason for revert:
[Sheriff] Breaks mac gc stress:
http://build.chromium.org/p/client.v8/builders/V8%20Mac%20GC%20Stress/builds/1024

Original issue's description:
> [strong] checking of this & super in constructors
>
> R=dslomov@chromium.org, marja@chromium.org
> BUG=v8:3956
> LOG=N
>
> Enforces for constructors that
> - the only use of 'super' is the super constructor call
> - the only use of 'this' is a property assignment
> - both of these must happen at the top-level of the body
> - 'this' may only be assigned after the 'super' call
> - 'return' may only be used after the last assignment to 'this'
>
> Not yet working for arrow functions (there might be deeper bugs with those).
>
> Committed: https://crrev.com/580d66bcda66220d2f3062ac58daf925436df74c
> Cr-Commit-Position: refs/heads/master@{#27977}

TBR=dslomov@chromium.org,marja@chromium.org,conradw@chromium.org,rossberg@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:3956

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

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

src/messages.js
src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
test/cctest/test-parsing.cc
test/mjsunit/strong/classes.js

index f50e8e7..04e107d 100644 (file)
@@ -143,11 +143,9 @@ var kMessages = {
   strong_unbound_global:         ["In strong mode, using an undeclared global variable '", "%0", "' is not allowed"],
   strong_super_call_missing:     ["In strong mode, invoking the super constructor in a subclass is required"],
   strong_super_call_duplicate:   ["In strong mode, invoking the super constructor multiple times is deprecated"],
-  strong_super_call_misplaced:   ["In strong mode, the super constructor must be invoked before any assignment to 'this'"],
-  strong_constructor_super:      ["In strong mode, 'super' can only be used to invoke the super constructor, and cannot be nested inside another statement or expression"],
-  strong_constructor_this:       ["In strong mode, 'this' can only be used to initialize properties, and cannot be nested inside another statement or expression"],
+  strong_super_call_nested:      ["In strong mode, invoking the super constructor nested inside another statement or expression is deprecated"],
   strong_constructor_return_value: ["In strong mode, returning a value from a constructor is deprecated"],
-  strong_constructor_return_misplaced: ["In strong mode, returning from a constructor before its super constructor invocation or all assignments to 'this' is deprecated"],
+  strong_constructor_return_misplaced: ["In strong mode, returning from a constructor before its super constructor invocation is deprecated"],
   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"],
   cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
index 2961a1a..c73b6d8 100644 (file)
@@ -1210,28 +1210,25 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
       directive_prologue = false;
     }
 
+    Token::Value token = peek();
     Scanner::Location token_loc = scanner()->peek_location();
-    Scanner::Location old_this_loc = function_state_->this_location();
-    Scanner::Location old_super_loc = function_state_->super_location();
+    Scanner::Location old_super_loc = function_state_->super_call_location();
     Statement* stat = ParseStatementListItem(CHECK_OK);
+    Scanner::Location super_loc = function_state_->super_call_location();
 
     if (is_strong(language_mode()) &&
-        scope_->is_function_scope() &&
-        i::IsConstructor(function_state_->kind())) {
-      Scanner::Location this_loc = function_state_->this_location();
-      Scanner::Location super_loc = function_state_->super_location();
-      if (this_loc.beg_pos != old_this_loc.beg_pos &&
-          this_loc.beg_pos != token_loc.beg_pos) {
-        ReportMessageAt(this_loc, "strong_constructor_this");
-        *ok = false;
-        return nullptr;
-      }
-      if (super_loc.beg_pos != old_super_loc.beg_pos &&
-          super_loc.beg_pos != token_loc.beg_pos) {
-        ReportMessageAt(super_loc, "strong_constructor_super");
-        *ok = false;
-        return nullptr;
-      }
+        i::IsConstructor(function_state_->kind()) &&
+        !old_super_loc.IsValid() && super_loc.IsValid() &&
+        token != Token::SUPER) {
+      // TODO(rossberg): This is more permissive than spec'ed, it allows e.g.
+      //   super(), 1;
+      //   super() + "";
+      //   super() = 0;
+      // That should still be safe, though, thanks to left-to-right evaluation.
+      // The proper check would be difficult to implement in the preparser.
+      ReportMessageAt(super_loc, "strong_super_call_nested");
+      *ok = false;
+      return NULL;
     }
 
     if (stat == NULL || stat->IsEmpty()) {
@@ -2596,8 +2593,6 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
   // ExpressionStatement[Yield] :
   //   [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ;
 
-  int pos = peek_position();
-
   switch (peek()) {
     case Token::FUNCTION:
     case Token::LBRACE:
@@ -2607,37 +2602,6 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
       *ok = false;
       return nullptr;
 
-    case Token::THIS:
-    case Token::SUPER:
-      if (is_strong(language_mode()) &&
-          i::IsConstructor(function_state_->kind())) {
-        bool is_this = peek() == Token::THIS;
-        Expression* expr;
-        if (is_this) {
-          expr = ParseStrongInitializationExpression(CHECK_OK);
-        } else {
-          expr = ParseStrongSuperCallExpression(CHECK_OK);
-        }
-        switch (peek()) {
-          case Token::SEMICOLON:
-            Consume(Token::SEMICOLON);
-            break;
-          case Token::RBRACE:
-          case Token::EOS:
-            break;
-          default:
-            if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
-              ReportMessageAt(function_state_->this_location(),
-                              is_this ? "strong_constructor_this"
-                                      : "strong_constructor_super");
-              *ok = false;
-              return nullptr;
-            }
-        }
-        return factory()->NewExpressionStatement(expr, pos);
-      }
-      break;
-
     // TODO(arv): Handle `let [`
     // https://code.google.com/p/v8/issues/detail?id=3847
 
@@ -2645,6 +2609,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
       break;
   }
 
+  int pos = peek_position();
   bool starts_with_idenfifier = peek_any_identifier();
   Expression* expr = ParseExpression(true, CHECK_OK);
   if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
@@ -4038,7 +4003,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     parenthesized_function_ = false;  // The bit was set for this function only.
 
     if (is_lazily_parsed) {
-      SkipLazyFunctionBody(&materialized_literal_count,
+      SkipLazyFunctionBody(function_name, &materialized_literal_count,
                            &expected_property_count, CHECK_OK);
     } else {
       body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
@@ -4046,15 +4011,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
       materialized_literal_count = function_state.materialized_literal_count();
       expected_property_count = function_state.expected_property_count();
       handler_count = function_state.handler_count();
-
-      if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
-        if (!function_state.super_location().IsValid()) {
-          ReportMessageAt(function_name_location,
-                          "strong_super_call_missing", kReferenceError);
-          *ok = false;
-          return nullptr;
-        }
-      }
     }
 
     // Validate name and parameter names. We can do this only after parsing the
@@ -4069,8 +4025,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     if (is_strict(language_mode())) {
       CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
                               CHECK_OK);
+    }
+    if (is_strict(language_mode())) {
       CheckConflictingVarDeclarations(scope, CHECK_OK);
     }
+    if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
+      if (!function_state.super_call_location().IsValid()) {
+        ReportMessageAt(function_name_location, "strong_super_call_missing",
+                        kReferenceError);
+        *ok = false;
+        return nullptr;
+      }
+    }
   }
 
   FunctionLiteral::ParameterFlag duplicate_parameters =
@@ -4094,7 +4060,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 }
 
 
-void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
+void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
+                                  int* materialized_literal_count,
                                   int* expected_property_count,
                                   bool* ok) {
   if (produce_cached_parse_data()) CHECK(log_);
index b4c628e..3b3144e 100644 (file)
@@ -773,7 +773,8 @@ class ParserTraits {
       bool name_is_strict_reserved, FunctionKind kind,
       int function_token_position, FunctionLiteral::FunctionType type,
       FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
-  V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
+  V8_INLINE void SkipLazyFunctionBody(const AstRawString* name,
+                                      int* materialized_literal_count,
                                       int* expected_property_count, bool* ok);
   V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
       const AstRawString* name, int pos, Variable* fvar,
@@ -1024,7 +1025,8 @@ class Parser : public ParserBase<ParserTraits> {
 
   // Skip over a lazy function, either using cached data if we have it, or
   // by parsing the function with PreParser. Consumes the ending }.
-  void SkipLazyFunctionBody(int* materialized_literal_count,
+  void SkipLazyFunctionBody(const AstRawString* function_name,
+                            int* materialized_literal_count,
                             int* expected_property_count,
                             bool* ok);
 
@@ -1089,11 +1091,12 @@ const AstRawString* ParserTraits::EmptyIdentifierString() {
 }
 
 
-void ParserTraits::SkipLazyFunctionBody(int* materialized_literal_count,
+void ParserTraits::SkipLazyFunctionBody(const AstRawString* function_name,
+                                        int* materialized_literal_count,
                                         int* expected_property_count,
                                         bool* ok) {
   return parser_->SkipLazyFunctionBody(
-      materialized_literal_count, expected_property_count, ok);
+      function_name, materialized_literal_count, expected_property_count, ok);
 }
 
 
index caa383a..4a8c37d 100644 (file)
@@ -123,15 +123,6 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
     if (is_strict(scope_->language_mode())) {
       int end_pos = scanner()->location().end_pos;
       CheckStrictOctalLiteral(start_position, end_pos, &ok);
-      if (!ok) return kPreParseSuccess;
-
-      if (is_strong(scope_->language_mode()) && IsSubclassConstructor(kind)) {
-        if (!function_state.super_location().IsValid()) {
-          ReportMessageAt(Scanner::Location(start_position, start_position + 1),
-                          "strong_super_call_missing", kReferenceError);
-          return kPreParseSuccess;
-        }
-      }
     }
   }
   return kPreParseSuccess;
@@ -205,31 +196,19 @@ void PreParser::ParseStatementList(int end_token, bool* ok) {
     if (directive_prologue && peek() != Token::STRING) {
       directive_prologue = false;
     }
-    Scanner::Location token_loc = scanner()->peek_location();
-    Scanner::Location old_this_loc = function_state_->this_location();
-    Scanner::Location old_super_loc = function_state_->super_location();
+    Token::Value token = peek();
+    Scanner::Location old_super_loc = function_state_->super_call_location();
     Statement statement = ParseStatementListItem(ok);
     if (!*ok) return;
-
+    Scanner::Location super_loc = function_state_->super_call_location();
     if (is_strong(language_mode()) &&
-        scope_->is_function_scope() &&
-        i::IsConstructor(function_state_->kind())) {
-      Scanner::Location this_loc = function_state_->this_location();
-      Scanner::Location super_loc = function_state_->super_location();
-      if (this_loc.beg_pos != old_this_loc.beg_pos &&
-          this_loc.beg_pos != token_loc.beg_pos) {
-        ReportMessageAt(this_loc, "strong_constructor_this");
-        *ok = false;
-        return;
-      }
-      if (super_loc.beg_pos != old_super_loc.beg_pos &&
-          super_loc.beg_pos != token_loc.beg_pos) {
-        ReportMessageAt(super_loc, "strong_constructor_super");
-        *ok = false;
-        return;
-      }
+        i::IsConstructor(function_state_->kind()) &&
+        !old_super_loc.IsValid() && super_loc.IsValid() &&
+        token != Token::SUPER) {
+      ReportMessageAt(super_loc, "strong_super_call_nested");
+      *ok = false;
+      return;
     }
-
     if (directive_prologue) {
       if (statement.IsUseStrictLiteral()) {
         scope_->SetLanguageMode(
@@ -553,37 +532,6 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
       *ok = false;
       return Statement::Default();
 
-    case Token::THIS:
-    case Token::SUPER:
-      if (is_strong(language_mode()) &&
-          i::IsConstructor(function_state_->kind())) {
-        bool is_this = peek() == Token::THIS;
-        Expression expr = Expression::Default();
-        if (is_this) {
-          expr = ParseStrongInitializationExpression(CHECK_OK);
-        } else {
-          expr = ParseStrongSuperCallExpression(CHECK_OK);
-        }
-        switch (peek()) {
-          case Token::SEMICOLON:
-            Consume(Token::SEMICOLON);
-            break;
-          case Token::RBRACE:
-          case Token::EOS:
-            break;
-          default:
-            if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
-              ReportMessageAt(function_state_->this_location(),
-                              is_this ? "strong_constructor_this"
-                                      : "strong_constructor_super");
-              *ok = false;
-              return Statement::Default();
-            }
-        }
-        return Statement::ExpressionStatement(expr);
-      }
-      break;
-
     // TODO(arv): Handle `let [`
     // https://code.google.com/p/v8/issues/detail?id=3847
 
@@ -1024,7 +972,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
   }
 
   if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
-    if (!function_state.super_location().IsValid()) {
+    if (!function_state.super_call_location().IsValid()) {
       ReportMessageAt(function_name_location, "strong_super_call_missing",
                       kReferenceError);
       *ok = false;
index 0d71d93..0643c30 100644 (file)
@@ -233,18 +233,16 @@ class ParserBase : public Traits {
     void AddProperty() { expected_property_count_++; }
     int expected_property_count() { return expected_property_count_; }
 
-    Scanner::Location this_location() const { return this_location_; }
-    Scanner::Location super_location() const { return super_location_; }
     Scanner::Location return_location() const { return return_location_; }
-    void set_this_location(Scanner::Location location) {
-      this_location_ = location;
-    }
-    void set_super_location(Scanner::Location location) {
-      super_location_ = location;
+    Scanner::Location super_call_location() const {
+      return super_call_location_;
     }
     void set_return_location(Scanner::Location location) {
       return_location_ = location;
     }
+    void set_super_call_location(Scanner::Location location) {
+      super_call_location_ = location;
+    }
 
     bool is_generator() const { return IsGeneratorFunction(kind_); }
 
@@ -276,14 +274,11 @@ class ParserBase : public Traits {
     // Properties count estimation.
     int expected_property_count_;
 
-    // Location of most recent use of 'this' (invalid if none).
-    Scanner::Location this_location_;
-
     // Location of most recent 'return' statement (invalid if none).
     Scanner::Location return_location_;
 
     // Location of call to the "super" constructor (invalid if none).
-    Scanner::Location super_location_;
+    Scanner::Location super_call_location_;
 
     FunctionKind kind_;
     // For generators, this variable may hold the generator object. It variable
@@ -632,8 +627,6 @@ class ParserBase : public Traits {
   ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok);
   void AddTemplateExpression(ExpressionT);
   ExpressionT ParseSuperExpression(bool is_new, bool* ok);
-  ExpressionT ParseStrongInitializationExpression(bool* ok);
-  ExpressionT ParseStrongSuperCallExpression(bool* ok);
 
   void ParseFormalParameter(FormalParameterScopeT* scope,
                             FormalParameterErrorLocations* locs, bool is_rest,
@@ -1555,7 +1548,8 @@ class PreParserTraits {
     return PreParserExpressionList();
   }
 
-  V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
+  V8_INLINE void SkipLazyFunctionBody(PreParserIdentifier function_name,
+                                      int* materialized_literal_count,
                                       int* expected_property_count, bool* ok) {
     UNREACHABLE();
   }
@@ -1738,7 +1732,8 @@ class PreParser : public ParserBase<PreParserTraits> {
   Expression ParseObjectLiteral(bool* ok);
   Expression ParseV8Intrinsic(bool* ok);
 
-  V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
+  V8_INLINE void SkipLazyFunctionBody(PreParserIdentifier function_name,
+                                      int* materialized_literal_count,
                                       int* expected_property_count, bool* ok);
   V8_INLINE PreParserStatementList
   ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
@@ -1834,9 +1829,8 @@ ParserBase<Traits>::FunctionState::FunctionState(
     : next_materialized_literal_index_(0),
       next_handler_index_(0),
       expected_property_count_(0),
-      this_location_(Scanner::Location::invalid()),
       return_location_(Scanner::Location::invalid()),
-      super_location_(Scanner::Location::invalid()),
+      super_call_location_(Scanner::Location::invalid()),
       kind_(kind),
       generator_object_variable_(NULL),
       function_state_stack_(function_state_stack),
@@ -2051,15 +2045,6 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
   switch (token) {
     case Token::THIS: {
       Consume(Token::THIS);
-      if (is_strong(language_mode())) {
-        // Constructors' usages of 'this' in strong mode are parsed separately.
-        // TODO(rossberg): this does not work with arrow functions yet.
-        if (i::IsConstructor(function_state_->kind())) {
-          ReportMessage("strong_constructor_this");
-          *ok = false;
-          break;
-        }
-      }
       scope_->RecordThisUsage();
       result = this->ThisExpression(scope_, factory(), beg_pos);
       break;
@@ -2132,7 +2117,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
     case Token::CLASS: {
       Consume(Token::CLASS);
       if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
-        ReportMessage("sloppy_lexical");
+        ReportMessage("sloppy_lexical", NULL);
         *ok = false;
         break;
       }
@@ -3020,141 +3005,9 @@ ParserBase<Traits>::ParseMemberExpression(bool* ok) {
 
 template <class Traits>
 typename ParserBase<Traits>::ExpressionT
-ParserBase<Traits>::ParseStrongInitializationExpression(bool* ok) {
-  // InitializationExpression ::  (strong mode)
-  //  'this' '.' IdentifierName '=' AssignmentExpression
-  //  'this' '[' Expression ']' '=' AssignmentExpression
-
-  if (fni_ != NULL) fni_->Enter();
-
-  Consume(Token::THIS);
-  int pos = position();
-  function_state_->set_this_location(scanner()->location());
-  scope_->RecordThisUsage();
-  ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
-
-  ExpressionT left = this->EmptyExpression();
-  switch (peek()) {
-    case Token::LBRACK: {
-      Consume(Token::LBRACK);
-      int pos = position();
-      ExpressionT index = this->ParseExpression(true, CHECK_OK);
-      left = factory()->NewProperty(this_expr, index, pos);
-      if (fni_ != NULL) {
-        this->PushPropertyName(fni_, index);
-      }
-      Expect(Token::RBRACK, CHECK_OK);
-      break;
-    }
-    case Token::PERIOD: {
-      Consume(Token::PERIOD);
-      int pos = position();
-      IdentifierT name = ParseIdentifierName(CHECK_OK);
-      left = factory()->NewProperty(
-          this_expr, factory()->NewStringLiteral(name, pos), pos);
-      if (fni_ != NULL) {
-        this->PushLiteralName(fni_, name);
-      }
-      break;
-    }
-    default:
-      ReportMessage("strong_constructor_this");
-      *ok = false;
-      return this->EmptyExpression();
-  }
-
-  if (peek() != Token::ASSIGN) {
-    ReportMessageAt(function_state_->this_location(),
-                    "strong_constructor_this");
-    *ok = false;
-    return this->EmptyExpression();
-  }
-  Consume(Token::ASSIGN);
-  left = this->MarkExpressionAsAssigned(left);
-
-  ExpressionT right = this->ParseAssignmentExpression(true, CHECK_OK);
-  this->CheckAssigningFunctionLiteralToProperty(left, right);
-  function_state_->AddProperty();
-  if (fni_ != NULL) {
-    // Check if the right hand side is a call to avoid inferring a
-    // name if we're dealing with "this.a = function(){...}();"-like
-    // expression.
-    if (!right->IsCall() && !right->IsCallNew()) {
-      fni_->Infer();
-    } else {
-      fni_->RemoveLastFunction();
-    }
-    fni_->Leave();
-  }
-
-  if (function_state_->return_location().IsValid()) {
-    ReportMessageAt(function_state_->return_location(),
-                    "strong_constructor_return_misplaced");
-    *ok = false;
-    return this->EmptyExpression();
-  }
-
-  return factory()->NewAssignment(Token::ASSIGN, left, right, pos);
-}
-
-
-template <class Traits>
-typename ParserBase<Traits>::ExpressionT
-ParserBase<Traits>::ParseStrongSuperCallExpression(bool* ok) {
-  // SuperCallExpression ::  (strong mode)
-  //  'super' '(' ExpressionList ')'
-
-  Consume(Token::SUPER);
-  int pos = position();
-  Scanner::Location super_loc = scanner()->location();
-  ExpressionT expr = this->SuperReference(scope_, factory());
-
-  if (peek() != Token::LPAREN) {
-    ReportMessage("strong_constructor_super");
-    *ok = false;
-    return this->EmptyExpression();
-  }
-
-  Scanner::Location spread_pos;
-  typename Traits::Type::ExpressionList args =
-      ParseArguments(&spread_pos, CHECK_OK);
-
-  // TODO(rossberg): This doesn't work with arrow functions yet.
-  if (!IsSubclassConstructor(function_state_->kind())) {
-    ReportMessage("unexpected_super");
-    *ok = false;
-    return this->EmptyExpression();
-  } else if (function_state_->super_location().IsValid()) {
-    ReportMessageAt(scanner()->location(), "strong_super_call_duplicate");
-    *ok = false;
-    return this->EmptyExpression();
-  } else if (function_state_->this_location().IsValid()) {
-    ReportMessageAt(scanner()->location(), "strong_super_call_misplaced");
-    *ok = false;
-    return this->EmptyExpression();
-  } else if (function_state_->return_location().IsValid()) {
-    ReportMessageAt(function_state_->return_location(),
-                    "strong_constructor_return_misplaced");
-    *ok = false;
-    return this->EmptyExpression();
-  }
-
-  function_state_->set_super_location(super_loc);
-  if (spread_pos.IsValid()) {
-    args = Traits::PrepareSpreadArguments(args);
-    return Traits::SpreadCall(expr, args, pos);
-  } else {
-    return factory()->NewCall(expr, args, pos);
-  }
-}
-
-
-template <class Traits>
-typename ParserBase<Traits>::ExpressionT
 ParserBase<Traits>::ParseSuperExpression(bool is_new, bool* ok) {
   Expect(Token::SUPER, CHECK_OK);
 
-  // TODO(wingo): Does this actually work with lazily compiled arrows?
   FunctionState* function_state = function_state_;
   while (IsArrowFunction(function_state->kind())) {
     function_state = function_state->outer();
@@ -3172,12 +3025,18 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new, bool* ok) {
     // super() is only allowed in derived constructor
     if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
       if (is_strong(language_mode())) {
-        // Super calls in strong mode are parsed separately.
-        ReportMessageAt(scanner()->location(), "strong_constructor_super");
-        *ok = false;
-        return this->EmptyExpression();
+        if (function_state->super_call_location().IsValid()) {
+          ReportMessageAt(scanner()->location(), "strong_super_call_duplicate");
+          *ok = false;
+          return this->EmptyExpression();
+        } else if (function_state->return_location().IsValid()) {
+          ReportMessageAt(function_state->return_location(),
+                          "strong_constructor_return_misplaced");
+          *ok = false;
+          return this->EmptyExpression();
+        }
       }
-      function_state->set_super_location(scanner()->location());
+      function_state->set_super_call_location(scanner()->location());
       return this->SuperReference(scope_, factory());
     }
   }
@@ -3374,7 +3233,8 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
           (mode() == PARSE_LAZILY && scope_->AllowsLazyCompilation());
       if (is_lazily_parsed) {
         body = this->NewStatementList(0, zone());
-        this->SkipLazyFunctionBody(&materialized_literal_count,
+        this->SkipLazyFunctionBody(this->EmptyIdentifier(),
+                                   &materialized_literal_count,
                                    &expected_property_count, CHECK_OK);
       } else {
         body = this->ParseEagerFunctionBody(
@@ -3396,7 +3256,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
       expected_property_count = function_state.expected_property_count();
       handler_count = function_state.handler_count();
     }
-    super_loc = function_state.super_location();
+    super_loc = function_state.super_call_location();
 
     scope->set_end_position(scanner()->location().end_pos);
 
@@ -3425,7 +3285,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
       scope->start_position());
 
   function_literal->set_function_token_position(scope->start_position());
-  if (super_loc.IsValid()) function_state_->set_super_location(super_loc);
+  if (super_loc.IsValid()) function_state_->set_super_call_location(super_loc);
 
   if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
 
index ba84258..86e042e 100644 (file)
@@ -5866,109 +5866,33 @@ TEST(StrongForIn) {
 }
 
 
-TEST(StrongConstructorThis) {
+TEST(StrongSuperCalls) {
   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* error_data[] = {
-      "class C { constructor() { this; } }",
-      "class C { constructor() { this.a; } }",
-      "class C { constructor() { this['a']; } }",
-      "class C { constructor() { (this); } }",
-      "class C { constructor() { this(); } }",
-      // TODO(rossberg): arrow functions not handled yet.
-      // "class C { constructor() { () => this; } }",
-      "class C { constructor() { this.a = 0, 0; } }",
-      "class C { constructor() { (this.a = 0); } }",
-      // "class C { constructor() { (() => this.a = 0)(); } }",
-      "class C { constructor() { { this.a = 0; } } }",
-      "class C { constructor() { if (1) this.a = 0; } }",
-      "class C { constructor() { label: this.a = 0; } }",
-      "class C { constructor() { this.a = this.b; } }",
-      "class C { constructor() { this.a = {b: 1}; this.a.b } }",
-      "class C { constructor() { this.a = {b: 1}; this.a.b = 0 } }",
-      "class C { constructor() { this.a = function(){}; this.a() } }",
-      NULL};
-
-  const char* success_data[] = {
-      "class C { constructor() { this.a = 0; } }",
-      "class C { constructor() { label: 0; this.a = 0; this.b = 6; } }",
-      NULL};
-
-  static const ParserFlag always_flags[] = {
-      kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals,
-      kAllowHarmonyArrowFunctions
-  };
-  RunParserSyncTest(sloppy_context_data, error_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strict_context_data, error_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strong_context_data, error_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-
-  RunParserSyncTest(sloppy_context_data, success_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strict_context_data, success_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strong_context_data, success_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-}
-
-
-TEST(StrongConstructorSuper) {
-  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* error_data[] = {
+  const char* data[] = {
       "class C extends Object { constructor() {} }",
-      "class C extends Object { constructor() { super.a; } }",
-      "class C extends Object { constructor() { super['a']; } }",
-      "class C extends Object { constructor() { super.a = 0; } }",
-      "class C extends Object { constructor() { (super.a); } }",
-      // TODO(rossberg): arrow functions do not handle super yet.
-      // "class C extends Object { constructor() { () => super.a; } }",
-      "class C extends Object { constructor() { super(), 0; } }",
       "class C extends Object { constructor() { (super()); } }",
-      // "class C extends Object { constructor() { (() => super())(); } }",
+      "class C extends Object { constructor() { (() => super())(); } }",
       "class C extends Object { constructor() { { super(); } } }",
       "class C extends Object { constructor() { if (1) super(); } }",
-      "class C extends Object { constructor() { label: super(); } }",
       "class C extends Object { constructor() { super(), super(); } }",
       "class C extends Object { constructor() { super(); super(); } }",
       "class C extends Object { constructor() { super(); (super()); } }",
       "class C extends Object { constructor() { super(); { super() } } }",
-      "class C extends Object { constructor() { this.a = 0, super(); } }",
-      "class C extends Object { constructor() { this.a = 0; super(); } }",
-      "class C extends Object { constructor() { super(this.a = 0); } }",
-      "class C extends Object { constructor() { super().a; } }",
-      NULL};
-
-  const char* success_data[] = {
-      "class C extends Object { constructor() { super(); } }",
-      "class C extends Object { constructor() { label: 66; super(); } }",
-      "class C extends Object { constructor() { super(3); this.x = 0; } }",
-      "class C extends Object { constructor() { 3; super(3); this.x = 0; } }",
       NULL};
 
   static const ParserFlag always_flags[] = {
       kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals,
       kAllowHarmonyArrowFunctions
   };
-  RunParserSyncTest(sloppy_context_data, error_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strict_context_data, error_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strong_context_data, error_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-
-  RunParserSyncTest(sloppy_context_data, success_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strict_context_data, success_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strong_context_data, success_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
+  RunParserSyncTest(sloppy_context_data, data, kError, 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));
 }
 
 
@@ -5977,45 +5901,24 @@ TEST(StrongConstructorReturns) {
   const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
   const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
 
-  const char* error_data[] = {
+  const char* data[] = {
       "class C extends Object { constructor() { super(); return {}; } }",
       "class C extends Object { constructor() { super(); { return {}; } } }",
       "class C extends Object { constructor() { super(); if (1) return {}; } }",
       "class C extends Object { constructor() { return; super(); } }",
       "class C extends Object { constructor() { { return; } super(); } }",
       "class C extends Object { constructor() { if (0) return; super(); } }",
-      "class C { constructor() { return; this.a = 0; } }",
-      "class C { constructor() { { return; } this.a = 0; } }",
-      "class C { constructor() { if (0) return; this.a = 0; } }",
-      "class C { constructor() { this.a = 0; if (0) return; this.b = 0; } }",
-      NULL};
-
-  const char* success_data[] = {
-      "class C extends Object { constructor() { super(); return; } }",
-      "class C extends Object { constructor() { super(); { return } } }",
-      "class C extends Object { constructor() { super(); if (1) return; } }",
-      "class C { constructor() { this.a = 0; return; } }",
-      "class C { constructor() { this.a = 0; { return; }  } }",
-      "class C { constructor() { this.a = 0; if (0) return; 65; } }",
-      "class C extends Array { constructor() { super(); this.a = 9; return } }",
       NULL};
 
   static const ParserFlag always_flags[] = {
       kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals
   };
-  RunParserSyncTest(sloppy_context_data, error_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strict_context_data, error_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strong_context_data, error_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-
-  RunParserSyncTest(sloppy_context_data, success_data, kError, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strict_context_data, success_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
-  RunParserSyncTest(strong_context_data, success_data, kSuccess, NULL, 0,
-                    always_flags, arraysize(always_flags));
+  RunParserSyncTest(sloppy_context_data, data, kError, 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 c329043..50fe5a1 100644 (file)
@@ -28,32 +28,16 @@ function constructor(body) {
       "(class extends Object { constructor() { " + body + " } })";
 }
 
-(function NoSuperExceptCall() {
-  assertSyntaxError(constructor("super.a;"));
-  assertSyntaxError(constructor("super['a'];"));
-  assertSyntaxError(constructor("super.f();"));
-  assertSyntaxError(constructor("super.a;"));
-  assertSyntaxError(constructor("{ super.a }"));
-  assertSyntaxError(constructor("if (0) super.a;"));
-  // TODO(rossberg): arrow functions do not handle 'super' yet.
-  // assertSyntaxError(constructor("() => super.a;"));
-  // assertSyntaxError(constructor("() => () => super.a;"));
-  // assertSyntaxError(constructor("() => { () => if (0) { super.a; } }"));
-})();
-
 (function NoMissingSuper() {
   assertReferenceError(constructor(""));
   assertReferenceError(constructor("1"));
 })();
 
 (function NoNestedSuper() {
-  assertSyntaxError(constructor("super(), 0;"));
   assertSyntaxError(constructor("(super());"));
-  assertSyntaxError(constructor("super().a;"));
   assertSyntaxError(constructor("(() => super())();"));
   assertSyntaxError(constructor("{ super(); }"));
   assertSyntaxError(constructor("if (1) super();"));
-  assertSyntaxError(constructor("label: super();"));
 })();
 
 (function NoDuplicateSuper() {
@@ -64,19 +48,9 @@ function constructor(body) {
   assertSyntaxError(constructor("super(); (() => super())();"));
 })();
 
-(function NoSuperAfterThis() {
-  assertSyntaxError(constructor("this.a = 0, super();"));
-  assertSyntaxError(constructor("this.a = 0; super();"));
-  assertSyntaxError(constructor("this.a = 0; super(); this.b = 0;"));
-  assertSyntaxError(constructor("this.a = 0; (super());"));
-  assertSyntaxError(constructor("super(this.a = 0);"));
-})();
-
 (function NoReturnValue() {
   assertSyntaxError(constructor("return {};"));
   assertSyntaxError(constructor("return undefined;"));
-  assertSyntaxError(constructor("return this;"));
-  assertSyntaxError(constructor("return this.a = 0;"));
   assertSyntaxError(constructor("{ return {}; }"));
   assertSyntaxError(constructor("if (1) return {};"));
 })();
@@ -86,34 +60,3 @@ function constructor(body) {
   assertSyntaxError(constructor("if (0) return; super();"));
   assertSyntaxError(constructor("{ return; } super();"));
 })();
-
-(function NoReturnBeforeThis() {
-  assertSyntaxError(constructor("return; this.a = 0;"));
-  assertSyntaxError(constructor("if (0) return; this.a = 0;"));
-  assertSyntaxError(constructor("{ return; } this.a = 0;"));
-})();
-
-(function NoThisExceptInitialization() {
-  assertSyntaxError(constructor("this;"));
-  assertSyntaxError(constructor("this.a;"));
-  assertSyntaxError(constructor("this['a'];"));
-  assertSyntaxError(constructor("this();"));
-  assertSyntaxError(constructor("this.a();"));
-  assertSyntaxError(constructor("this.a.b = 0;"));
-  assertSyntaxError(constructor("{ this }"));
-  assertSyntaxError(constructor("if (0) this;"));
-  // TODO(rossberg): this does not handle arrow functions yet.
-  // assertSyntaxError(constructor("() => this;"));
-  // assertSyntaxError(constructor("() => () => this;"));
-  // assertSyntaxError(constructor("() => { () => if (0) { this; } }"));
-})();
-
-(function NoNestedThis() {
-  assertSyntaxError(constructor("(this.a = 0);"));
-  assertSyntaxError(constructor("{ this.a = 0; }"));
-  assertSyntaxError(constructor("if (0) this.a = 0;"));
-  // TODO(rossberg): this does not handle arrow functions yet.
-  // assertSyntaxError(constructor("() => this.a = 0;"));
-  // assertSyntaxError(constructor("() => { this.a = 0; }"));
-  assertSyntaxError(constructor("label: this.a = 0;"));
-})();