[parser] disallow language mode directive in body of function with non-simple parameters
authorconradw <conradw@chromium.org>
Wed, 26 Aug 2015 14:59:05 +0000 (07:59 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 26 Aug 2015 14:59:19 +0000 (14:59 +0000)
TC39 agreed to disallow "use strict" directives in function body when
non-simple parameter lists are used.

This is a continuation of caitp's CL https://codereview.chromium.org/1281163002/
with some refactorings removed for now.

Still TODO: there is a lot of duplication between the is_simple field of
FormalParametersBase and the NonSimpleParameter property ExpressionClassifier
keeps track of. It should be possible to remove the former with a minor
refactoring of arrow function parsing. This will be attempted in a follow-up CL.

BUG=
LOG=N

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

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

17 files changed:
src/expression-classifier.h
src/messages.h
src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
src/scopes.cc
src/scopes.h
test/cctest/test-parsing.cc
test/mjsunit/harmony/arrow-rest-params.js
test/mjsunit/harmony/default-parameters.js
test/mjsunit/harmony/destructuring.js
test/mjsunit/harmony/rest-params.js
test/mjsunit/harmony/spread-call-super-property.js
test/mjsunit/strong/destructuring.js
test/mjsunit/strong/function-arity.js
test/mjsunit/strong/literals.js

index 17a377890add55a9d427a509ab5fdd205d5e833b..80f5e66fd4fea08d2f648824b1caee9ff4ae65d6 100644 (file)
@@ -45,11 +45,17 @@ class ExpressionClassifier {
                       ArrowFormalParametersProduction)
   };
 
+  enum FunctionProperties { NonSimpleParameter = 1 << 0 };
+
   ExpressionClassifier()
-      : invalid_productions_(0), duplicate_finder_(nullptr) {}
+      : invalid_productions_(0),
+        function_properties_(0),
+        duplicate_finder_(nullptr) {}
 
   explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
-      : invalid_productions_(0), duplicate_finder_(duplicate_finder) {}
+      : invalid_productions_(0),
+        function_properties_(0),
+        duplicate_finder_(duplicate_finder) {}
 
   bool is_valid(unsigned productions) const {
     return (invalid_productions_ & productions) == 0;
@@ -111,6 +117,14 @@ class ExpressionClassifier {
     return strong_mode_formal_parameter_error_;
   }
 
+  bool is_simple_parameter_list() const {
+    return !(function_properties_ & NonSimpleParameter);
+  }
+
+  void RecordNonSimpleParameter() {
+    function_properties_ |= NonSimpleParameter;
+  }
+
   void RecordExpressionError(const Scanner::Location& loc,
                              MessageTemplate::Template message,
                              const char* arg = nullptr) {
@@ -216,15 +230,21 @@ class ExpressionClassifier {
     // As an exception to the above, the result continues to be a valid arrow
     // formal parameters if the inner expression is a valid binding pattern.
     if (productions & ArrowFormalParametersProduction &&
-        is_valid_arrow_formal_parameters() &&
-        !inner.is_valid_binding_pattern()) {
-      invalid_productions_ |= ArrowFormalParametersProduction;
-      arrow_formal_parameters_error_ = inner.binding_pattern_error_;
+        is_valid_arrow_formal_parameters()) {
+      // Also copy function properties if expecting an arrow function
+      // parameter.
+      function_properties_ |= inner.function_properties_;
+
+      if (!inner.is_valid_binding_pattern()) {
+        invalid_productions_ |= ArrowFormalParametersProduction;
+        arrow_formal_parameters_error_ = inner.binding_pattern_error_;
+      }
     }
   }
 
  private:
   unsigned invalid_productions_;
+  unsigned function_properties_;
   Error expression_error_;
   Error binding_pattern_error_;
   Error assignment_pattern_error_;
index d293b74182f46b56178d5ad366c052112355aaa3..f08135bb16e17c5db3d713a3514a418f12b44536 100644 (file)
@@ -296,6 +296,8 @@ class CallSite {
   T(IllegalAccess, "Illegal access")                                           \
   T(IllegalBreak, "Illegal break statement")                                   \
   T(IllegalContinue, "Illegal continue statement")                             \
+  T(IllegalLanguageModeDirective,                                              \
+    "Illegal '%' directive in function with non-simple parameter list")        \
   T(IllegalReturn, "Illegal return statement")                                 \
   T(InvalidLhsInAssignment, "Invalid left-hand side in assignment")            \
   T(InvalidLhsInFor, "Invalid left-hand side in for-loop")                     \
index 2e6e0ad1cfab6aebc322c3cf930eb178fb370ec1..7ddd0fce0c804b2924ce422307c0e0b12110ed07 100644 (file)
@@ -1198,9 +1198,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
           // BindingIdentifier
           ParseFormalParameter(&formals, &formals_classifier, &ok);
           if (ok) {
-            DeclareFormalParameter(
-                formals.scope, formals.at(0), formals.is_simple,
-                &formals_classifier);
+            DeclareFormalParameter(formals.scope, formals.at(0),
+                                   &formals_classifier);
           }
         }
       }
@@ -1322,6 +1321,20 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
             token_loc.end_pos - token_loc.beg_pos ==
                 ast_value_factory()->use_strong_string()->length() + 2;
         if (use_strict_found || use_strong_found) {
+          if (!scope_->HasSimpleParameters()) {
+            // TC39 deemed "use strict" directives to be an error when occurring
+            // in the body of a function with non-simple parameter list, on
+            // 29/7/2015. https://goo.gl/ueA7Ln
+            //
+            // In V8, this also applies to "use strong " directives.
+            const AstRawString* string = literal->raw_value()->AsString();
+            ParserTraits::ReportMessageAt(
+                token_loc, MessageTemplate::kIllegalLanguageModeDirective,
+                string);
+            *ok = false;
+            return nullptr;
+          }
+
           // Strong mode implies strict mode. If there are several "use strict"
           // / "use strong" directives, do the strict mode changes only once.
           if (is_sloppy(scope_->language_mode())) {
@@ -3889,8 +3902,7 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
 
 void ParserTraits::ParseArrowFunctionFormalParameters(
     ParserFormalParameters* parameters, Expression* expr,
-    const Scanner::Location& params_loc,
-    Scanner::Location* duplicate_loc, bool* ok) {
+    const Scanner::Location& params_loc, bool* ok) {
   if (parameters->Arity() >= Code::kMaxArguments) {
     ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
     *ok = false;
@@ -3917,8 +3929,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
     DCHECK_EQ(binop->op(), Token::COMMA);
     Expression* left = binop->left();
     Expression* right = binop->right();
-    ParseArrowFunctionFormalParameters(parameters, left, params_loc,
-                                       duplicate_loc, ok);
+    ParseArrowFunctionFormalParameters(parameters, left, params_loc, ok);
     if (!*ok) return;
     // LHS of comma expression should be unparenthesized.
     expr = right;
@@ -3962,15 +3973,16 @@ void ParserTraits::ParseArrowFunctionFormalParameterList(
     Scanner::Location* duplicate_loc, bool* ok) {
   if (expr->IsEmptyParentheses()) return;
 
-  ParseArrowFunctionFormalParameters(parameters, expr, params_loc,
-                                     duplicate_loc, ok);
+  ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
   if (!*ok) return;
 
+  ExpressionClassifier classifier;
+  if (!parameters->is_simple) {
+    classifier.RecordNonSimpleParameter();
+  }
   for (int i = 0; i < parameters->Arity(); ++i) {
     auto parameter = parameters->at(i);
-    ExpressionClassifier classifier;
-    DeclareFormalParameter(
-        parameters->scope, parameter, parameters->is_simple, &classifier);
+    DeclareFormalParameter(parameters->scope, parameter, &classifier);
     if (!duplicate_loc->IsValid()) {
       *duplicate_loc = classifier.duplicate_formal_parameter_error().location;
     }
@@ -4585,7 +4597,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
 #undef SET_ALLOW
   }
   PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
-      language_mode(), function_state_->kind(), logger, bookmark);
+      language_mode(), function_state_->kind(), scope_->has_simple_parameters(),
+      logger, bookmark);
   if (pre_parse_timer_ != NULL) {
     pre_parse_timer_->Stop();
   }
index 746e08dc8aab66a4ef6abb742afb52b805f483a3..effa562e2bc9d25862bd37e8d57ac6ae9f87ee57 100644 (file)
@@ -786,11 +786,11 @@ class ParserTraits {
       Expression* initializer, bool is_rest);
   V8_INLINE void DeclareFormalParameter(
       Scope* scope, const ParserFormalParameters::Parameter& parameter,
-      bool is_simple, ExpressionClassifier* classifier);
-  void ParseArrowFunctionFormalParameters(
-      ParserFormalParameters* parameters, Expression* params,
-      const Scanner::Location& params_loc,
-      Scanner::Location* duplicate_loc, bool* ok);
+      ExpressionClassifier* classifier);
+  void ParseArrowFunctionFormalParameters(ParserFormalParameters* parameters,
+                                          Expression* params,
+                                          const Scanner::Location& params_loc,
+                                          bool* ok);
   void ParseArrowFunctionFormalParameterList(
       ParserFormalParameters* parameters, Expression* params,
       const Scanner::Location& params_loc,
@@ -1335,12 +1335,14 @@ void ParserTraits::AddFormalParameter(
 
 void ParserTraits::DeclareFormalParameter(
     Scope* scope, const ParserFormalParameters::Parameter& parameter,
-    bool is_simple, ExpressionClassifier* classifier) {
+    ExpressionClassifier* classifier) {
   bool is_duplicate = false;
+  bool is_simple = classifier->is_simple_parameter_list();
   // TODO(caitp): Remove special handling for rest once desugaring is in.
   auto name = is_simple || parameter.is_rest
       ? parameter.name : parser_->ast_value_factory()->empty_string();
   auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY;
+  if (!is_simple) scope->SetHasNonSimpleParameters();
   bool is_optional = parameter.initializer != nullptr;
   Variable* var = scope->DeclareParameter(
       name, mode, is_optional, parameter.is_rest, &is_duplicate);
index b1541f616afe133554881e99aec4f71a9f5e45e0..7e75e78ef9c2e0753c26e6f8bf9f5303ddc02f70 100644 (file)
@@ -102,8 +102,8 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral(
 
 
 PreParser::PreParseResult PreParser::PreParseLazyFunction(
-    LanguageMode language_mode, FunctionKind kind, ParserRecorder* log,
-    Scanner::BookmarkScope* bookmark) {
+    LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
+    ParserRecorder* log, Scanner::BookmarkScope* bookmark) {
   log_ = log;
   // Lazy functions always have trivial outer scopes (no with/catch scopes).
   Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE);
@@ -113,6 +113,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
   scope_->SetLanguageMode(language_mode);
   Scope* function_scope = NewScope(
       scope_, IsArrowFunction(kind) ? ARROW_SCOPE : FUNCTION_SCOPE, kind);
+  if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
   PreParserFactory function_factory(NULL);
   FunctionState function_state(&function_state_, &scope_, function_scope, kind,
                                &function_factory);
@@ -251,15 +252,33 @@ void PreParser::ParseStatementList(int end_token, bool* ok,
     }
 
     if (directive_prologue) {
-      if (statement.IsUseStrictLiteral()) {
+      bool use_strict_found = statement.IsUseStrictLiteral();
+      bool use_strong_found =
+          statement.IsUseStrongLiteral() && allow_strong_mode();
+
+      if (use_strict_found) {
         scope_->SetLanguageMode(
             static_cast<LanguageMode>(scope_->language_mode() | STRICT));
-      } else if (statement.IsUseStrongLiteral() && allow_strong_mode()) {
+      } else if (use_strong_found) {
         scope_->SetLanguageMode(static_cast<LanguageMode>(
             scope_->language_mode() | STRONG));
       } else if (!statement.IsStringLiteral()) {
         directive_prologue = false;
       }
+
+      if ((use_strict_found || use_strong_found) &&
+          !scope_->HasSimpleParameters()) {
+        // TC39 deemed "use strict" directives to be an error when occurring
+        // in the body of a function with non-simple parameter list, on
+        // 29/7/2015. https://goo.gl/ueA7Ln
+        //
+        // In V8, this also applies to "use strong " directives.
+        PreParserTraits::ReportMessageAt(
+            token_loc, MessageTemplate::kIllegalLanguageModeDirective,
+            use_strict_found ? "use strict" : "use strong");
+        *ok = false;
+        return;
+      }
     }
 
     // If we're allowed to reset to a bookmark, we will do so when we see a long
@@ -1057,7 +1076,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
   Expect(Token::LPAREN, CHECK_OK);
   int start_position = scanner()->location().beg_pos;
   function_scope->set_start_position(start_position);
-  PreParserFormalParameters formals(nullptr);
+  PreParserFormalParameters formals(function_scope);
   ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
   Expect(Token::RPAREN, CHECK_OK);
   int formals_end_position = scanner()->location().end_pos;
index e224bea1e70e47bf33a3d31ae3e529fcd3363dfb..07e431bfc54790b0a65c081f9ea8021ab6fba84c 100644 (file)
@@ -1648,8 +1648,11 @@ class PreParserTraits {
     ++parameters->arity;
   }
   void DeclareFormalParameter(Scope* scope, PreParserIdentifier parameter,
-                              bool is_simple,
-                              ExpressionClassifier* classifier) {}
+                              ExpressionClassifier* classifier) {
+    if (!classifier->is_simple_parameter_list()) {
+      scope->SetHasNonSimpleParameters();
+    }
+  }
 
   void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
 
@@ -1747,8 +1750,8 @@ class PreParser : public ParserBase<PreParserTraits> {
   // At return, unless an error occurred, the scanner is positioned before the
   // the final '}'.
   PreParseResult PreParseLazyFunction(
-      LanguageMode language_mode, FunctionKind kind, ParserRecorder* log,
-      Scanner::BookmarkScope* bookmark = nullptr);
+      LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
+      ParserRecorder* log, Scanner::BookmarkScope* bookmark = nullptr);
 
  private:
   friend class PreParserTraits;
@@ -2283,6 +2286,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
         classifier->RecordExpressionError(scanner()->location(),
                                           MessageTemplate::kUnexpectedToken,
                                           Token::String(Token::ELLIPSIS));
+        classifier->RecordNonSimpleParameter();
         Scanner::Location expr_loc = scanner()->peek_location();
         Token::Value tok = peek();
         result = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
@@ -2295,6 +2299,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
           return this->EmptyExpression();
         }
         result = factory()->NewSpread(result, ellipsis_pos);
+
         if (peek() == Token::COMMA) {
           ReportMessageAt(scanner()->peek_location(),
                           MessageTemplate::kParamAfterRest);
@@ -2385,6 +2390,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
       this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
   classifier->Accumulate(binding_classifier,
                          ExpressionClassifier::AllProductions);
+  bool is_simple_parameter_list = this->IsIdentifier(result);
   bool seen_rest = false;
   while (peek() == Token::COMMA) {
     if (seen_rest) {
@@ -2408,10 +2414,15 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
     ExpressionT right = this->ParseAssignmentExpression(
         accept_IN, &binding_classifier, CHECK_OK);
     if (is_rest) right = factory()->NewSpread(right, pos);
+    is_simple_parameter_list =
+        is_simple_parameter_list && this->IsIdentifier(right);
     classifier->Accumulate(binding_classifier,
                            ExpressionClassifier::AllProductions);
     result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
   }
+  if (!is_simple_parameter_list || seen_rest) {
+    classifier->RecordNonSimpleParameter();
+  }
   return result;
 }
 
@@ -2839,7 +2850,6 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
   }
   ExpressionT expression = this->ParseConditionalExpression(
       accept_IN, &arrow_formals_classifier, CHECK_OK);
-
   if (allow_harmony_arrow_functions() && peek() == Token::ARROW) {
     BindingPatternUnexpectedToken(classifier);
     ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
@@ -2848,6 +2858,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
     Scope* scope =
         this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
     FormalParametersT parameters(scope);
+    if (!arrow_formals_classifier.is_simple_parameter_list()) {
+      scope->SetHasNonSimpleParameters();
+      parameters.is_simple = false;
+    }
     checkpoint.Restore(&parameters.materialized_literals_count);
 
     scope->set_start_position(lhs_beg_pos);
@@ -3662,6 +3676,7 @@ void ParserBase<Traits>::ParseFormalParameter(
       return;
     }
     parameters->is_simple = false;
+    classifier->RecordNonSimpleParameter();
   }
 
   ExpressionT initializer = Traits::EmptyExpression();
@@ -3672,6 +3687,7 @@ void ParserBase<Traits>::ParseFormalParameter(
     ValidateExpression(&init_classifier, ok);
     if (!*ok) return;
     parameters->is_simple = false;
+    classifier->RecordNonSimpleParameter();
   }
 
   Traits::AddFormalParameter(parameters, pattern, initializer, is_rest);
@@ -3712,6 +3728,7 @@ void ParserBase<Traits>::ParseFormalParameterList(
 
     if (parameters->has_rest) {
       parameters->is_simple = false;
+      classifier->RecordNonSimpleParameter();
       if (peek() == Token::COMMA) {
         ReportMessageAt(scanner()->peek_location(),
                       MessageTemplate::kParamAfterRest);
@@ -3723,8 +3740,7 @@ void ParserBase<Traits>::ParseFormalParameterList(
 
   for (int i = 0; i < parameters->Arity(); ++i) {
     auto parameter = parameters->at(i);
-    Traits::DeclareFormalParameter(
-        parameters->scope, parameter, parameters->is_simple, classifier);
+    Traits::DeclareFormalParameter(parameters->scope, parameter, classifier);
   }
 }
 
index 8c99044e72b57a659ad49953331d04e129d62dac..0c8f2106802e4c8a6bab07d9ec132243198f95ce 100644 (file)
@@ -475,7 +475,6 @@ Variable* Scope::DeclareParameter(
   Variable* var;
   if (mode == TEMPORARY) {
     var = NewTemporary(name);
-    has_simple_parameters_ = false;
   } else {
     var = variables_.Declare(this, name, mode, Variable::NORMAL,
                              kCreatedInitialized);
@@ -489,7 +488,6 @@ Variable* Scope::DeclareParameter(
     DCHECK_NULL(rest_parameter_);
     rest_parameter_ = var;
     rest_index_ = num_parameters();
-    has_simple_parameters_ = false;
   }
   params_.Add(var, zone());
   return var;
index 4c36938e13c36920aad568c5624ccc3ae50a3f16..59965352058fe18ee26c0fa0e48c288eebbebcde 100644 (file)
@@ -387,10 +387,25 @@ class Scope: public ZoneObject {
   }
 
   bool has_simple_parameters() const {
-    DCHECK(is_function_scope());
     return has_simple_parameters_;
   }
 
+  // TODO(caitp): manage this state in a better way. PreParser must be able to
+  // communicate that the scope is non-simple, without allocating any parameters
+  // as the Parser does. This is necessary to ensure that TC39's proposed early
+  // error can be reported consistently regardless of whether lazily parsed or
+  // not.
+  void SetHasNonSimpleParameters() {
+    DCHECK(is_function_scope());
+    has_simple_parameters_ = false;
+  }
+
+  // Retrieve `IsSimpleParameterList` of current or outer function.
+  bool HasSimpleParameters() {
+    Scope* scope = ClosureScope();
+    return !scope->is_function_scope() || scope->has_simple_parameters();
+  }
+
   // The local variable 'arguments' if we need to allocate it; NULL otherwise.
   Variable* arguments() const {
     DCHECK(!is_arrow_scope() || arguments_ == nullptr);
index 1361bbcba78dc10dde5d2c5ef678068ef34482f7..1ea550caab1dc65b1fe0f320531bb250748c604d 100644 (file)
@@ -6925,3 +6925,90 @@ TEST(LetSloppy) {
   RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
                     arraysize(always_flags));
 }
+
+
+TEST(LanguageModeDirectivesNonSimpleParameterListErrors) {
+  // TC39 deemed "use strict" directives to be an error when occurring in the
+  // body of a function with non-simple parameter list, on 29/7/2015.
+  // https://goo.gl/ueA7Ln
+  //
+  // In V8, this also applies to "use strong " directives.
+  const char* context_data[][2] = {
+      {"function f(", ") { 'use strict'; }"},
+      {"function f(", ") { 'use strong'; }"},
+      {"function* g(", ") { 'use strict'; }"},
+      {"function* g(", ") { 'use strong'; }"},
+      {"class c { foo(", ") { 'use strict' }"},
+      {"class c { foo(", ") { 'use strong' }"},
+      {"var a = (", ") => { 'use strict'; }"},
+      {"var a = (", ") => { 'use strong'; }"},
+      {"var o = { m(", ") { 'use strict'; }"},
+      {"var o = { m(", ") { 'use strong'; }"},
+      {"var o = { *gm(", ") { 'use strict'; }"},
+      {"var o = { *gm(", ") { 'use strong'; }"},
+      {"var c = { m(", ") { 'use strict'; }"},
+      {"var c = { m(", ") { 'use strong'; }"},
+      {"var c = { *gm(", ") { 'use strict'; }"},
+      {"var c = { *gm(", ") { 'use strong'; }"},
+
+      {"'use strict'; function f(", ") { 'use strict'; }"},
+      {"'use strict'; function f(", ") { 'use strong'; }"},
+      {"'use strict'; function* g(", ") { 'use strict'; }"},
+      {"'use strict'; function* g(", ") { 'use strong'; }"},
+      {"'use strict'; class c { foo(", ") { 'use strict' }"},
+      {"'use strict'; class c { foo(", ") { 'use strong' }"},
+      {"'use strict'; var a = (", ") => { 'use strict'; }"},
+      {"'use strict'; var a = (", ") => { 'use strong'; }"},
+      {"'use strict'; var o = { m(", ") { 'use strict'; }"},
+      {"'use strict'; var o = { m(", ") { 'use strong'; }"},
+      {"'use strict'; var o = { *gm(", ") { 'use strict'; }"},
+      {"'use strict'; var o = { *gm(", ") { 'use strong'; }"},
+      {"'use strict'; var c = { m(", ") { 'use strict'; }"},
+      {"'use strict'; var c = { m(", ") { 'use strong'; }"},
+      {"'use strict'; var c = { *gm(", ") { 'use strict'; }"},
+      {"'use strict'; var c = { *gm(", ") { 'use strong'; }"},
+
+      {"'use strong'; function f(", ") { 'use strict'; }"},
+      {"'use strong'; function f(", ") { 'use strong'; }"},
+      {"'use strong'; function* g(", ") { 'use strict'; }"},
+      {"'use strong'; function* g(", ") { 'use strong'; }"},
+      {"'use strong'; class c { foo(", ") { 'use strict' }"},
+      {"'use strong'; class c { foo(", ") { 'use strong' }"},
+      {"'use strong'; var a = (", ") => { 'use strict'; }"},
+      {"'use strong'; var a = (", ") => { 'use strong'; }"},
+      {"'use strong'; var o = { m(", ") { 'use strict'; }"},
+      {"'use strong'; var o = { m(", ") { 'use strong'; }"},
+      {"'use strong'; var o = { *gm(", ") { 'use strict'; }"},
+      {"'use strong'; var o = { *gm(", ") { 'use strong'; }"},
+      {"'use strong'; var c = { m(", ") { 'use strict'; }"},
+      {"'use strong'; var c = { m(", ") { 'use strong'; }"},
+      {"'use strong'; var c = { *gm(", ") { 'use strict'; }"},
+      {"'use strong'; var c = { *gm(", ") { 'use strong'; }"},
+
+      {NULL, NULL}};
+
+  const char* data[] = {
+      // TODO(@caitp): support formal parameter initializers
+      "{}",
+      "[]",
+      "[{}]",
+      "{a}",
+      "a, {b}",
+      "a, b, {c, d, e}",
+      "initializer = true",
+      "a, b, c = 1",
+      "...args",
+      "a, b, ...rest",
+      "[a, b, ...rest]",
+      "{ bindingPattern = {} }",
+      "{ initializedBindingPattern } = { initializedBindingPattern: true }",
+      NULL};
+
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyArrowFunctions, kAllowHarmonyDefaultParameters,
+      kAllowHarmonyDestructuring, kAllowHarmonyRestParameters,
+      kAllowHarmonySloppy, kAllowStrongMode
+  };
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
index b1e8dcc1b99b484a9257b1f3a4c73ad5c94db0e1..0ee77390ed21496f590de890686891c29e7c3f96 100644 (file)
 //
 //   strictTest(6,5,4,3,2,1)
 //
-var strictTest = (a, b, ...c) => {
+var strictTest = (() => {
   "use strict";
-  assertEquals(Array, c.constructor);
-  assertTrue(Array.isArray(c));
+  return (a, b, ...c) => {
+    assertEquals(Array, c.constructor);
+    assertTrue(Array.isArray(c));
 
-  var expectedLength = (a === undefined) ? 0 : a - 2;
-  assertEquals(expectedLength, c.length);
+    var expectedLength = (a === undefined) ? 0 : a - 2;
+    assertEquals(expectedLength, c.length);
 
-  for (var i = 2; i < a; ++i) {
-    assertEquals(c[i - 2], a - i);
-  }
-}
+    for (var i = 2; i < a; ++i) {
+      assertEquals(c[i - 2], a - i);
+    }
+  };
+})();
 
 var sloppyTest = (a, b, ...c) => {
   assertEquals(Array, c.constructor);
index 0d87b0371217876779656f6a32568c065cecd365..b3a79a49a47a26ee9b989dfbd3cd0084e98c4010 100644 (file)
 })();
 
 
-(function TestParameterScoping() {
+(function TestParameterScopingSloppy() {
   var x = 1;
 
   function f1(a = x) { var x = 2; return a; }
   assertEquals(1, f1());
   function f2(a = x) { function x() {}; return a; }
   assertEquals(1, f2());
-  function f3(a = x) { 'use strict'; let x = 2; return a; }
+  function f3(a = eval("x")) { var x; return a; }
   assertEquals(1, f3());
-  function f4(a = x) { 'use strict'; const x = 2; return a; }
+  function f31(a = eval("'use strict'; x")) { var x; return a; }
+  assertEquals(1, f31());
+  function f4(a = function() { return x }) { var x; return a(); }
   assertEquals(1, f4());
-  function f5(a = x) { 'use strict'; function x() {}; return a; }
+  function f5(a = () => x) { var x; return a(); }
   assertEquals(1, f5());
-  function f6(a = eval("x")) { var x; return a; }
+  function f6(a = () => eval("x")) { var x; return a(); }
   assertEquals(1, f6());
-  function f61(a = eval("x")) { 'use strict'; var x; return a; }
+  function f61(a = () => { 'use strict'; return eval("x") }) { var x; return a(); }
   assertEquals(1, f61());
-  function f62(a = eval("'use strict'; x")) { var x; return a; }
+  function f62(a = () => eval("'use strict'; x")) { var x; return a(); }
   assertEquals(1, f62());
-  function f7(a = function() { return x }) { var x; return a(); }
-  assertEquals(1, f7());
-  function f8(a = () => x) { var x; return a(); }
-  assertEquals(1, f8());
-  function f9(a = () => eval("x")) { var x; return a(); }
-  assertEquals(1, f9());
-  function f91(a = () => eval("x")) { 'use strict'; var x; return a(); }
-  assertEquals(1, f91());
-  function f92(a = () => { 'use strict'; return eval("x") }) { var x; return a(); }
-  assertEquals(1, f92());
-  function f93(a = () => eval("'use strict'; x")) { var x; return a(); }
-  assertEquals(1, f93());
 
   var g1 = (a = x) => { var x = 2; return a; };
   assertEquals(1, g1());
   var g2 = (a = x) => { function x() {}; return a; };
   assertEquals(1, g2());
-  var g3 = (a = x) => { 'use strict'; let x = 2; return a; };
+  var g3 = (a = eval("x")) => { var x; return a; };
   assertEquals(1, g3());
-  var g4 = (a = x) => { 'use strict'; const x = 2; return a; };
+  var g31 = (a = eval("'use strict'; x")) => { var x; return a; };
+  assertEquals(1, g31());
+  var g4 = (a = function() { return x }) => { var x; return a(); };
   assertEquals(1, g4());
-  var g5 = (a = x) => { 'use strict'; function x() {}; return a; };
+  var g5 = (a = () => x) => { var x; return a(); };
   assertEquals(1, g5());
-  var g6 = (a = eval("x")) => { var x; return a; };
+  var g6 = (a = () => eval("x")) => { var x; return a(); };
   assertEquals(1, g6());
-  var g61 = (a = eval("x")) => { 'use strict'; var x; return a; };
+  var g61 = (a = () => { 'use strict'; return eval("x") }) => { var x; return a(); };
   assertEquals(1, g61());
-  var g62 = (a = eval("'use strict'; x")) => { var x; return a; };
+  var g62 = (a = () => eval("'use strict'; x")) => { var x; return a(); };
   assertEquals(1, g62());
-  var g7 = (a = function() { return x }) => { var x; return a(); };
-  assertEquals(1, g7());
-  var g8 = (a = () => x) => { var x; return a(); };
-  assertEquals(1, g8());
-  var g9 = (a = () => eval("x")) => { var x; return a(); };
-  assertEquals(1, g9());
-  var g91 = (a = () => eval("x")) => { 'use strict'; var x; return a(); };
-  assertEquals(1, g91());
-  var g92 = (a = () => { 'use strict'; return eval("x") }) => { var x; return a(); };
-  assertEquals(1, g92());
-  var g93 = (a = () => eval("'use strict'; x")) => { var x; return a(); };
-  assertEquals(1, g93());
 
   var f11 = function f(x = f) { var f; return x; }
   assertSame(f11, f11());
   var f12 = function f(x = f) { function f() {}; return x; }
   assertSame(f12, f12());
-  var f13 = function f(x = f) { 'use strict'; let f; return x; }
-  assertSame(f13, f13());
-  var f14 = function f(x = f) { 'use strict'; const f = 0; return x; }
-  assertSame(f14, f14());
-  var f15 = function f(x = f) { 'use strict'; function f() {}; return x; }
-  assertSame(f15, f15());
-  var f16 = function f(f = 7, x = f) { return x; }
-  assertSame(7, f16());
+  var f13 = function f(f = 7, x = f) { return x; }
+  assertSame(7, f13());
 
   var o1 = {f: function(x = this) { return x; }};
   assertSame(o1, o1.f());
   assertSame(1, o1.f(1));
 })();
 
+(function TestParameterScopingStrict() {
+  "use strict";
+  var x = 1;
+
+  function f1(a = x) { let x = 2; return a; }
+  assertEquals(1, f1());
+  function f2(a = x) { const x = 2; return a; }
+  assertEquals(1, f2());
+  function f3(a = x) { function x() {}; return a; }
+  assertEquals(1, f3());
+  function f4(a = eval("x")) { var x; return a; }
+  assertEquals(1, f4());
+  function f5(a = () => eval("x")) { var x; return a(); }
+  assertEquals(1, f5());
+
+  var g1 = (a = x) => { let x = 2; return a; };
+  assertEquals(1, g1());
+  var g2 = (a = x) => { const x = 2; return a; };
+  assertEquals(1, g2());
+  var g3 = (a = x) => { function x() {}; return a; };
+  assertEquals(1, g3());
+  var g4 = (a = eval("x")) => { var x; return a; };
+  assertEquals(1, g4());
+  var g5 = (a = () => eval("x")) => { var x; return a(); };
+  assertEquals(1, g5());
+
+  var f11 = function f(x = f) { let f; return x; }
+  assertSame(f11, f11());
+  var f12 = function f(x = f) { const f = 0; return x; }
+  assertSame(f12, f12());
+  var f13 = function f(x = f) { function f() {}; return x; }
+  assertSame(f13, f13());
+})();
 
 (function TestSloppyEvalScoping() {
   var x = 1;
   assertEquals(3, f22(() => 3));
 })();
 
-
-(function TestParameterTDZ() {
+(function TestParameterTDZSloppy() {
   function f1(a = x, x) { return a }
   assertThrows(() => f1(undefined, 4), ReferenceError);
   assertEquals(4, f1(4, 5));
   function f2(a = eval("x"), x) { return a }
   assertThrows(() => f2(undefined, 4), ReferenceError);
   assertEquals(4, f2(4, 5));
-  function f3(a = eval("x"), x) { 'use strict'; return a }
+  function f3(a = eval("'use strict'; x"), x) { return a }
   assertThrows(() => f3(undefined, 4), ReferenceError);
   assertEquals(4, f3(4, 5));
-  function f4(a = eval("'use strict'; x"), x) { return a }
-  assertThrows(() => f4(undefined, 4), ReferenceError);
-  assertEquals(4, f4(4, 5));
-
-  function f5(a = () => x, x) { return a() }
+  function f4(a = () => x, x) { return a() }
+  assertEquals(4, f4(() => 4, 5));
+  function f5(a = () => eval("x"), x) { return a() }
   assertEquals(4, f5(() => 4, 5));
-  function f6(a = () => eval("x"), x) { return a() }
+  function f6(a = () => eval("'use strict'; x"), x) { return a() }
   assertEquals(4, f6(() => 4, 5));
-  function f7(a = () => eval("x"), x) { 'use strict'; return a() }
-  assertEquals(4, f7(() => 4, 5));
-  function f8(a = () => eval("'use strict'; x"), x) { return a() }
-  assertEquals(4, f8(() => 4, 5));
 
   function f11(a = x, x = 2) { return a }
   assertThrows(() => f11(), ReferenceError);
   assertThrows(() => f12(undefined), ReferenceError);
   assertThrows(() => f12(undefined, 4), ReferenceError);
   assertEquals(4, f12(4, 5));
-  function f13(a = eval("x"), x = 2) { 'use strict'; return a }
+  function f13(a = eval("'use strict'; x"), x = 2) { return a }
   assertThrows(() => f13(), ReferenceError);
   assertThrows(() => f13(undefined), ReferenceError);
   assertThrows(() => f13(undefined, 4), ReferenceError);
   assertEquals(4, f13(4, 5));
-  function f14(a = eval("'use strict'; x"), x = 2) { return a }
-  assertThrows(() => f14(), ReferenceError);
-  assertThrows(() => f14(undefined), ReferenceError);
-  assertThrows(() => f14(undefined, 4), ReferenceError);
-  assertEquals(4, f14(4, 5));
-
-  function f34(x = function() { return a }, ...a) { return x()[0] }
-  assertEquals(4, f34(undefined, 4));
-  function f35(x = () => a, ...a) { return x()[0] }
-  assertEquals(4, f35(undefined, 4));
-  function f36(x = () => eval("a"), ...a) { return x()[0] }
-  assertEquals(4, f36(undefined, 4));
-  function f37(x = () => eval("a"), ...a) { 'use strict'; return x()[0] }
-  assertEquals(4, f37(undefined, 4));
-  function f38(x = () => { 'use strict'; return eval("a") }, ...a) { return x()[0] }
-  assertEquals(4, f38(undefined, 4));
-  function f39(x = () => eval("'use strict'; a"), ...a) { return x()[0] }
-  assertEquals(4, f39(undefined, 4));
-
-  var g34 = (x = function() { return a }, ...a) => { return x()[0] };
-  assertEquals(4, g34(undefined, 4));
-  var g35 = (x = () => a, ...a) => { return x()[0] };
-  assertEquals(4, g35(undefined, 4));
+
+  function f21(x = function() { return a }, ...a) { return x()[0] }
+  assertEquals(4, f21(undefined, 4));
+  function f22(x = () => a, ...a) { return x()[0] }
+  assertEquals(4, f22(undefined, 4));
+  function f23(x = () => eval("a"), ...a) { return x()[0] }
+  assertEquals(4, f23(undefined, 4));
+  function f24(x = () => {'use strict'; return eval("a") }, ...a) {
+    return x()[0]
+  }
+  assertEquals(4, f24(undefined, 4));
+  function f25(x = () => eval("'use strict'; a"), ...a) { return x()[0] }
+  assertEquals(4, f25(undefined, 4));
+
+  var g1 = (x = function() { return a }, ...a) => { return x()[0] };
+  assertEquals(4, g1(undefined, 4));
+  var g2 = (x = () => a, ...a) => { return x()[0] };
+  assertEquals(4, g2(undefined, 4));
 })();
 
+(function TestParameterTDZStrict() {
+  "use strict";
+
+  function f1(a = eval("x"), x) { return a }
+  assertThrows(() => f1(undefined, 4), ReferenceError);
+  assertEquals(4, f1(4, 5));
+  function f2(a = () => eval("x"), x) { return a() }
+  assertEquals(4, f2(() => 4, 5));
+
+  function f11(a = eval("x"), x = 2) { return a }
+  assertThrows(() => f11(), ReferenceError);
+  assertThrows(() => f11(undefined), ReferenceError);
+  assertThrows(() => f11(undefined, 4), ReferenceError);
+  assertEquals(4, f11(4, 5));
+
+  function f21(x = () => eval("a"), ...a) { return x()[0] }
+  assertEquals(4, f21(undefined, 4));
+})();
 
 (function TestArgumentsForNonSimpleParameters() {
   function f1(x = 900) { arguments[0] = 1; return x }
    assertEquals(1, (function(x, y = 1, z, v = 2) {}).length);
    assertEquals(1, (function(x, y = 1, z, v = 2, ...a) {}).length);
 })();
+
+(function TestDirectiveThrows() {
+  "use strict";
+
+  assertThrows(function(){ eval("function(x=1){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(x=1) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(x=1) {'use strict';}});") }, SyntaxError);
+
+  assertThrows(
+    function(){ eval("function(a, x=1){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(a, x=1) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(a, x=1) {'use strict';}});") }, SyntaxError);
+})();
index 84eeb893f0a08aeb9f3191a275952e21c48a9bba..703e521912eb2b6bee292c9271142fa08028c477 100644 (file)
   assertEquals(1, f1({}));
   function f2({a = x}) { function x() {}; return a; }
   assertEquals(1, f2({}));
-  function f3({a = x}) { 'use strict'; let x = 2; return a; }
-  assertEquals(1, f3({}));
-  function f4({a = x}) { 'use strict'; const x = 2; return a; }
-  assertEquals(1, f4({}));
-  function f5({a = x}) { 'use strict'; function x() {}; return a; }
-  assertEquals(1, f5({}));
+  (function() {
+    'use strict';
+    function f3({a = x}) { let x = 2; return a; }
+    assertEquals(1, f3({}));
+    function f4({a = x}) { const x = 2; return a; }
+    assertEquals(1, f4({}));
+    function f5({a = x}) { function x() {}; return a; }
+    assertEquals(1, f5({}));
+  })();
   function f6({a = eval("x")}) { var x; return a; }
   assertEquals(1, f6({}));
-  function f61({a = eval("x")}) { 'use strict'; var x; return a; }
-  assertEquals(1, f61({}));
+  (function() {
+    'use strict';
+    function f61({a = eval("x")}) { var x; return a; }
+    assertEquals(1, f61({}));
+  })();
   function f62({a = eval("'use strict'; x")}) { var x; return a; }
   assertEquals(1, f62({}));
   function f7({a = function() { return x }}) { var x; return a(); }
   assertEquals(1, f8({}));
   function f9({a = () => eval("x")}) { var x; return a(); }
   assertEquals(1, f9({}));
-  function f91({a = () => eval("x")}) { 'use strict'; var x; return a(); }
-  assertEquals(1, f91({}));
+  (function TestInitializedWithEvalArrowStrict() {
+    'use strict';
+    function f91({a = () => eval("x")}) { var x; return a(); }
+    assertEquals(1, f91({}));
+  })();
   function f92({a = () => { 'use strict'; return eval("x") }}) { var x; return a(); }
   assertEquals(1, f92({}));
   function f93({a = () => eval("'use strict'; x")}) { var x; return a(); }
   assertEquals(1, g1({}));
   var g2 = ({a = x}) => { function x() {}; return a; };
   assertEquals(1, g2({}));
-  var g3 = ({a = x}) => { 'use strict'; let x = 2; return a; };
-  assertEquals(1, g3({}));
-  var g4 = ({a = x}) => { 'use strict'; const x = 2; return a; };
-  assertEquals(1, g4({}));
-  var g5 = ({a = x}) => { 'use strict'; function x() {}; return a; };
-  assertEquals(1, g5({}));
+  (function() {
+    'use strict';
+    var g3 = ({a = x}) => { let x = 2; return a; };
+    assertEquals(1, g3({}));
+    var g4 = ({a = x}) => { const x = 2; return a; };
+    assertEquals(1, g4({}));
+    var g5 = ({a = x}) => { function x() {}; return a; };
+    assertEquals(1, g5({}));
+  })();
   var g6 = ({a = eval("x")}) => { var x; return a; };
   assertEquals(1, g6({}));
-  var g61 = ({a = eval("x")}) => { 'use strict'; var x; return a; };
-  assertEquals(1, g61({}));
+  (function() {
+    'use strict';
+    var g61 = ({a = eval("x")}) => { var x; return a; };
+    assertEquals(1, g61({}));
+  })();
   var g62 = ({a = eval("'use strict'; x")}) => { var x; return a; };
   assertEquals(1, g62({}));
   var g7 = ({a = function() { return x }}) => { var x; return a(); };
   assertEquals(1, g8({}));
   var g9 = ({a = () => eval("x")}) => { var x; return a(); };
   assertEquals(1, g9({}));
-  var g91 = ({a = () => eval("x")}) => { 'use strict'; var x; return a(); };
-  assertEquals(1, g91({}));
-  var g92 = ({a = () => { 'use strict'; return eval("x") }}) => { var x; return a(); };
-  assertEquals(1, g92({}));
+  (function() {
+    'use strict';
+    var g91 = ({a = () => eval("x")}) => { var x; return a(); };
+    assertEquals(1, g91({}));
+    var g92 = ({a = () => { return eval("x") }}) => { var x; return a(); };
+    assertEquals(1, g92({}));
+  })();
   var g93 = ({a = () => eval("'use strict'; x")}) => { var x; return a(); };
   assertEquals(1, g93({}));
 
   assertSame(f11, f11({}));
   var f12 = function f({x = f}) { function f() {}; return x; }
   assertSame(f12, f12({}));
-  var f13 = function f({x = f}) { 'use strict'; let f; return x; }
-  assertSame(f13, f13({}));
-  var f14 = function f({x = f}) { 'use strict'; const f = 0; return x; }
-  assertSame(f14, f14({}));
-  var f15 = function f({x = f}) { 'use strict'; function f() {}; return x; }
-  assertSame(f15, f15({}));
+  (function() {
+    'use strict';
+    var f13 = function f({x = f}) { let f; return x; }
+    assertSame(f13, f13({}));
+    var f14 = function f({x = f}) { const f = 0; return x; }
+    assertSame(f14, f14({}));
+    var f15 = function f({x = f}) { function f() {}; return x; }
+    assertSame(f15, f15({}));
+  })();
   var f16 = function f({f = 7, x = f}) { return x; }
   assertSame(7, f16({}));
 
   function f2({a = eval("x")}, x) { return a }
   assertThrows(() => f2({}, 4), ReferenceError);
   assertEquals(4, f2({a: 4}, 5));
-  function f3({a = eval("x")}, x) { 'use strict'; return a }
-  assertThrows(() => f3({}, 4), ReferenceError);
-  assertEquals(4, f3({a: 4}, 5));
+  (function() {
+    'use strict';
+    function f3({a = eval("x")}, x) { return a }
+    assertThrows(() => f3({}, 4), ReferenceError);
+    assertEquals(4, f3({a: 4}, 5));
+  })();
   function f4({a = eval("'use strict'; x")}, x) { return a }
   assertThrows(() => f4({}, 4), ReferenceError);
   assertEquals(4, f4({a: 4}, 5));
   assertEquals(4, f5({a: () => 4}, 5));
   function f6({a = () => eval("x")}, x) { return a() }
   assertEquals(4, f6({a: () => 4}, 5));
-  function f7({a = () => eval("x")}, x) { 'use strict'; return a() }
-  assertEquals(4, f7({a: () => 4}, 5));
+  (function() {
+    'use strict';
+    function f7({a = () => eval("x")}, x) { return a() }
+    assertEquals(4, f7({a: () => 4}, 5));
+  })();
   function f8({a = () => eval("'use strict'; x")}, x) { return a() }
   assertEquals(4, f8({a: () => 4}, 5));
 
   function f12({a = eval("b")}, {b}) { return a }
   assertThrows(() => f12({}, {b: 4}), ReferenceError);
   assertEquals(4, f12({a: 4}, {b: 5}));
-  function f13({a = eval("b")}, {b}) { 'use strict'; return a }
-  assertThrows(() => f13({}, {b: 4}), ReferenceError);
-  assertEquals(4, f13({a: 4}, {b: 5}));
+  (function() {
+    'use strict';
+    function f13({a = eval("b")}, {b}) { return a }
+    assertThrows(() => f13({}, {b: 4}), ReferenceError);
+    assertEquals(4, f13({a: 4}, {b: 5}));
+  })();
   function f14({a = eval("'use strict'; b")}, {b}) { return a }
   assertThrows(() => f14({}, {b: 4}), ReferenceError);
   assertEquals(4, f14({a: 4}, {b: 5}));
   assertEquals(4, f15({a: () => 4}, {b: 5}));
   function f16({a = () => eval("b")}, {b}) { return a() }
   assertEquals(4, f16({a: () => 4}, {b: 5}));
-  function f17({a = () => eval("b")}, {b}) { 'use strict'; return a() }
-  assertEquals(4, f17({a: () => 4}, {b: 5}));
+  (function() {
+    'use strict';
+    function f17({a = () => eval("b")}, {b}) { return a() }
+    assertEquals(4, f17({a: () => 4}, {b: 5}));
+  })();
   function f18({a = () => eval("'use strict'; b")}, {b}) { return a() }
   assertEquals(4, f18({a: () => 4}, {b: 5}));
 
   assertEquals(4, f35({}, 4));
   function f36({x = () => eval("a")}, ...a) { return x()[0] }
   assertEquals(4, f36({}, 4));
-  function f37({x = () => eval("a")}, ...a) { 'use strict'; return x()[0] }
-  assertEquals(4, f37({}, 4));
+  (function() {
+    'use strict';
+    function f37({x = () => eval("a")}, ...a) { return x()[0] }
+    assertEquals(4, f37({}, 4));
+  })();
   function f38({x = () => { 'use strict'; return eval("a") }}, ...a) { return x()[0] }
   assertEquals(4, f38({}, 4));
   function f39({x = () => eval("'use strict'; a")}, ...a) { return x()[0] }
    assertEquals(1, (function(x, {y} = {}, {z}, {v} = {}) {}).length);
    assertEquals(1, (function({x}, {y} = {}, {z}, {v} = {}, ...a) {}).length);
 })();
+
+
+(function TestDirectiveThrows() {
+  "use strict";
+
+  assertThrows(function(){ eval("function({}){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("({}) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo({}) {'use strict';}});") }, SyntaxError);
+
+  assertThrows(
+    function(){ eval("function(a, {}){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(a, {}) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(a, {}) {'use strict';}});") }, SyntaxError);
+})();
index fe7ee2adb81186076d1a32bee92642d1a2cdc430..49515f4f2c964678fb61e729ba0012a2edb112c0 100644 (file)
                     return args.length; })(1,2,3,4,5));
 })();
 
-function strictTest(a, b, ...c) {
+var strictTest = (function() {
   "use strict";
-  assertEquals(Array, c.constructor);
-  assertTrue(Array.isArray(c));
+  return function strictTest(a, b, ...c) {
+    assertEquals(Array, c.constructor);
+    assertTrue(Array.isArray(c));
 
-  var expectedLength = arguments.length >= 3 ? arguments.length - 2 : 0;
-  assertEquals(expectedLength, c.length);
+    var expectedLength = arguments.length >= 3 ? arguments.length - 2 : 0;
+    assertEquals(expectedLength, c.length);
 
-  for (var i = 2, j = 0; i < arguments.length; ++i) {
-    assertEquals(c[j++], arguments[i]);
-  }
-}
+    for (var i = 2, j = 0; i < arguments.length; ++i) {
+      assertEquals(c[j++], arguments[i]);
+    }
+  };
+})();
 
 function sloppyTest(a, b, ...c) {
   assertEquals(Array, c.constructor);
@@ -144,14 +146,15 @@ var O = {
 
 
 (function testNoAliasArgumentsStrict() {
-  function strictF(a, ...rest) {
+  ((function() {
     "use strict";
-    arguments[0] = 1;
-    assertEquals(3, a);
-    arguments[1] = 2;
-    assertArrayEquals([4, 5], rest);
-  }
-  strictF(3, 4, 5);
+    return (function strictF(a, ...rest) {
+              arguments[0] = 1;
+              assertEquals(3, a);
+              arguments[1] = 2;
+              assertArrayEquals([4, 5], rest);
+            });
+  })())(3, 4, 5);
 })();
 
 
@@ -212,3 +215,21 @@ var O = {
   assertEquals([1, 2, 3], c.child);
   assertEquals([1, 2, 3], c.base);
 })();
+
+(function TestDirectiveThrows() {
+  "use strict";
+
+  assertThrows(
+    function(){ eval("function(...rest){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(...rest) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(...rest) {'use strict';}});") }, SyntaxError);
+
+  assertThrows(
+    function(){ eval("function(a, ...rest){'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(a, ...rest) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(a, ...rest) {'use strict';}});") },
+    SyntaxError);
+})();
index cdf6f2e242268ab6df3bf5a9c378cfc7fe67e4bf..1eb2abc3b0433a99051b39f8b76775fbfea81b2a 100644 (file)
@@ -4,17 +4,28 @@
 
 // Flags: --harmony-spreadcalls --harmony-sloppy --harmony-rest-parameters
 
-(function testCallSuperProperty() {
+(function testCallSuperPropertyStrict() {
+  "use strict";
   class BaseClass {
-    strict_method(...args) { "use strict"; return [this].concat(args); }
-    sloppy_method(...args) { return [this].concat(args); }
+    method(...args) { return [this].concat(args); }
   }
   class SubClass extends BaseClass {
-    strict_m(...args) { return super.strict_method(...args); }
-    sloppy_m(...args) { return super.sloppy_method(...args); }
+    method(...args) { return super.method(...args); }
   }
 
   var c = new SubClass();
-  assertEquals([c, 1, 2, 3, 4, 5], c.strict_m(1, 2, 3, 4, 5));
-  assertEquals([c, 1, 2, 3, 4, 5], c.sloppy_m(1, 2, 3, 4, 5));
+  assertEquals([c, 1, 2, 3, 4, 5], c.method(1, 2, 3, 4, 5));
+})();
+
+
+(function testCallSuperPropertySloppy() {
+  class BaseClass {
+    method(...args) { return [this].concat(args); }
+  }
+  class SubClass extends BaseClass {
+    method(...args) { return super.method(...args); }
+  }
+
+  var c = new SubClass();
+  assertEquals([c, 1, 2, 3, 4, 5], c.method(1, 2, 3, 4, 5));
 })();
index 67fe2ef4f163a699fecf24e1721c4ed5c8b3d691..3145dcfb4d9312235c63ed894eb5db618235f135 100644 (file)
@@ -6,7 +6,10 @@
 // Flags: --harmony-arrow-functions --strong-mode --allow-natives-syntax
 
 (function() {
-  function f({ x = function() { return []; } }) { "use strong"; return x(); }
+  var f = (function() {
+    "use strong";
+    return function f({ x = function() { return []; } }) { return x(); };
+  })();
   var a = f({ x: undefined });
   assertTrue(%IsStrong(a));
 
   assertFalse(%IsStrong(a));
 
   function outerf() { return []; }
-  function f2({ x = outerf }) { "use strong"; return x(); }
+  var f2 = (function() {
+    "use strong";
+    return function f2({ x = outerf }) { return x(); };
+  })();
   a = f2({ x: undefined });
   assertFalse(%IsStrong(a));
 })();
index 4d8833564cc3dbe3d0de6968acd497959ed8d22c..8eddc5e4a73bc916790d6d7162601e9746dfea38 100644 (file)
@@ -21,7 +21,7 @@ function generateArguments(n, prefix) {
 }
 
 
-function generateParams(n) {
+function generateParams(n, directive_in_body) {
   let a = [];
   for (let i = 0; i < n; i++) {
     a[i] = `p${i}`;
@@ -29,13 +29,17 @@ function generateParams(n) {
   return a.join(', ');
 }
 
-function generateParamsWithRest(n) {
+function generateParamsWithRest(n, directive_in_body) {
   let a = [];
   let i = 0;
   for (; i < n; i++) {
     a[i] = `p${i}`;
   }
-  a.push(`...p${i}`)
+  if (!directive_in_body) {
+    // If language mode directive occurs in body, rest parameters will trigger
+    // an early error regardless of language mode.
+    a.push(`...p${i}`);
+  }
   return a.join(', ');
 }
 
@@ -76,6 +80,7 @@ function generateSpread(n) {
         for (let call of calls) {
           let code = `'use strict'; ${def}; ${call};`;
           if (argumentCount < parameterCount) {
+            print(code);
             assertThrows(code, TypeError);
           } else {
             assertDoesNotThrow(code);
@@ -106,13 +111,13 @@ function generateSpread(n) {
     for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
       let defs = [
         `let o = new class {
-          m(${genParams(parameterCount)}) { 'use strong'; }
+          m(${genParams(parameterCount, true)}) { 'use strong'; }
         }`,
         `let o = new class {
-          *m(${genParams(parameterCount)}) { 'use strong'; }
+          *m(${genParams(parameterCount, true)}) { 'use strong'; }
         }`,
-        `let o = { m(${genParams(parameterCount)}) { 'use strong'; } }`,
-        `let o = { *m(${genParams(parameterCount)}) { 'use strong'; } }`,
+        `let o = { m(${genParams(parameterCount, true)}) { 'use strong'; } }`,
+        `let o = { *m(${genParams(parameterCount, true)}) { 'use strong'; } }`,
         `'use strong';
         let o = new class { m(${genParams(parameterCount)}) {} }`,
         `'use strong';
@@ -173,7 +178,7 @@ function generateSpread(n) {
           class C { constructor(${genParams(parameterCount)}) {} }`,
           `'use strict';
           class C {
-            constructor(${genParams(parameterCount)}) { 'use strong'; }
+            constructor(${genParams(parameterCount, true)}) { 'use strong'; }
           }`,
         ];
         for (let def of defs) {
@@ -214,7 +219,7 @@ function generateSpread(n) {
             }`,
             `'use strict';
             class B {
-              constructor(${genParams(parameterCount)}) { 'use strong'; }
+              constructor(${genParams(parameterCount, true)}) { 'use strong'; }
             }
             class C extends B {
               constructor() {
@@ -250,7 +255,7 @@ function generateSpread(n) {
             class C extends B {}`,
             `'use strict';
             class B {
-              constructor(${genParams(parameterCount)}) { 'use strong'; }
+              constructor(${genParams(parameterCount, true)}) { 'use strong'; }
             }
             class C extends B {}`,
           ];
index 8c04d6e35a7f7ed2fd48a30052d92b5e145cf96a..28123c218ee1d7675f36164758378d7c25940c7c 100644 (file)
   assertWeakArray({a: [], b: {}}.a);
 })();
 
-(function StrongArrayLiterals(...args) {
+(function StrongArrayLiterals() {
   'use strong';
   function assertStrongArray(x) {
     assertTrue(%IsStrong(x));
     assertSame(Array.prototype, Object.getPrototypeOf(x));
   }
   let [...r] = [];
-  assertStrongArray(args);
+  assertStrongArray((function(...a) { return a; })());
   assertStrongArray(r);
   assertStrongArray([]);
   assertStrongArray([1, 2, 3]);