[destructuring] Implement parameter pattern matching.
authordslomov <dslomov@chromium.org>
Mon, 22 Jun 2015 12:06:55 +0000 (05:06 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 22 Jun 2015 12:07:13 +0000 (12:07 +0000)
Scoping for initializers is yet incorrect. Defaults are not supported.

R=arv@chromium.org,rossberg@chromium.org
BUG=v8:811
LOG=N

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

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

src/parser.cc
src/parser.h
src/pattern-rewriter.cc
src/preparser.cc
src/preparser.h
src/scopes.cc
test/cctest/test-parsing.cc
test/mjsunit/harmony/destructuring.js
test/mjsunit/regress/regress-1130.js
test/mjsunit/regress/regress-436896.js
test/webkit/fast/js/arguments-expected.txt

index 7e0d9366116f3b8bd7619a78ceb39e6a6901cd1e..61385929bc5962d2955d32788a117ce2cc88670a 100644 (file)
@@ -1182,7 +1182,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
           NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
       scope->set_start_position(shared_info->start_position());
       ExpressionClassifier formals_classifier;
-      bool has_rest = false;
+      ParserFormalParameterParsingState parsing_state(scope);
       {
         // Parsing patterns as variable reference expression creates
         // NewUnresolved references in current scope. Entrer arrow function
@@ -1190,17 +1190,19 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
         BlockState block_state(&scope_, scope);
         if (Check(Token::LPAREN)) {
           // '(' StrictFormalParameters ')'
-          ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok);
+          ParseFormalParameterList(&parsing_state, &formals_classifier, &ok);
           if (ok) ok = Check(Token::RPAREN);
         } else {
           // BindingIdentifier
-          ParseFormalParameter(scope, has_rest, &formals_classifier, &ok);
+          const bool is_rest = false;
+          ParseFormalParameter(is_rest, &parsing_state, &formals_classifier,
+                               &ok);
         }
       }
 
       if (ok) {
         Expression* expression =
-            ParseArrowFunctionLiteral(scope, has_rest, formals_classifier, &ok);
+            ParseArrowFunctionLiteral(parsing_state, formals_classifier, &ok);
         if (ok) {
           // Scanning must end at the same position that was recorded
           // previously. If not, parsing has been interrupted due to a stack
@@ -1547,7 +1549,7 @@ ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
     VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
     ImportDeclaration* declaration =
         factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
-    Declare(declaration, true, CHECK_OK);
+    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
     result->Add(declaration, zone());
     if (peek() == Token::RBRACE) break;
     Expect(Token::COMMA, CHECK_OK);
@@ -1595,7 +1597,8 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
     VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
     import_default_declaration = factory()->NewImportDeclaration(
         proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
-    Declare(import_default_declaration, true, CHECK_OK);
+    Declare(import_default_declaration, DeclarationDescriptor::NORMAL, true,
+            CHECK_OK);
   }
 
   const AstRawString* module_instance_binding = NULL;
@@ -1982,7 +1985,9 @@ VariableProxy* Parser::NewUnresolved(const AstRawString* name,
 }
 
 
-Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
+Variable* Parser::Declare(Declaration* declaration,
+                          DeclarationDescriptor::Kind declaration_kind,
+                          bool resolve, bool* ok) {
   VariableProxy* proxy = declaration->proxy();
   DCHECK(proxy->raw_name() != NULL);
   const AstRawString* name = proxy->raw_name();
@@ -2041,11 +2046,15 @@ Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
       if (is_strict(language_mode())) {
         // In harmony we treat re-declarations as early errors. See
         // ES5 16 for a definition of early errors.
-        ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
+        if (declaration_kind == DeclarationDescriptor::NORMAL) {
+          ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
+        } else {
+          ParserTraits::ReportMessage(MessageTemplate::kStrictParamDupe);
+        }
         *ok = false;
         return nullptr;
       }
-      Expression* expression = NewThrowTypeError(
+      Expression* expression = NewThrowSyntaxError(
           MessageTemplate::kVarRedeclaration, name, declaration->position());
       declaration_scope->SetIllegalRedeclaration(expression);
     } else if (mode == VAR) {
@@ -2155,7 +2164,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
   VariableProxy* proxy = NewUnresolved(name, VAR);
   Declaration* declaration =
       factory()->NewVariableDeclaration(proxy, VAR, scope_, pos);
-  Declare(declaration, true, CHECK_OK);
+  Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
   NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral(
       name, extension_, RelocInfo::kNoPosition);
   return factory()->NewExpressionStatement(
@@ -2200,7 +2209,7 @@ Statement* Parser::ParseFunctionDeclaration(
   VariableProxy* proxy = NewUnresolved(name, mode);
   Declaration* declaration =
       factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
-  Declare(declaration, true, CHECK_OK);
+  Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
   if (names) names->Add(name, zone());
   return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
 }
@@ -2241,7 +2250,8 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
   Declaration* declaration = factory()->NewVariableDeclaration(
       proxy, mode, scope_, pos, is_class_declaration,
       scope_->class_declaration_group_start());
-  Variable* outer_class_variable = Declare(declaration, true, CHECK_OK);
+  Variable* outer_class_variable =
+      Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
   proxy->var()->set_initializer_position(position());
   // This is needed because a class ("class Name { }") creates two bindings (one
   // in the outer scope, and one in the class scope). The method is a function
@@ -2397,6 +2407,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
   //   BindingPattern '=' AssignmentExpression
 
   parsing_result->descriptor.parser = this;
+  parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
   parsing_result->descriptor.declaration_pos = peek_position();
   parsing_result->descriptor.initialization_pos = peek_position();
   parsing_result->descriptor.mode = VAR;
@@ -3328,7 +3339,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
     VariableProxy* proxy = NewUnresolved(names->at(i), mode);
     Declaration* declaration = factory()->NewVariableDeclaration(
         proxy, mode, scope_, RelocInfo::kNoPosition);
-    Declare(declaration, true, CHECK_OK);
+    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
     inner_vars.Add(declaration->proxy()->var(), zone());
     VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
     Assignment* assignment =
@@ -3784,9 +3795,10 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
 
 
 void ParserTraits::ParseArrowFunctionFormalParameters(
-    Scope* scope, Expression* expr, const Scanner::Location& params_loc,
-    bool* has_rest, Scanner::Location* duplicate_loc, bool* ok) {
-  if (scope->num_parameters() >= Code::kMaxArguments) {
+    ParserFormalParameterParsingState* parsing_state, Expression* expr,
+    const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
+    bool* ok) {
+  if (parsing_state->scope->num_parameters() >= Code::kMaxArguments) {
     ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
     *ok = false;
     return;
@@ -3812,7 +3824,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
     DCHECK_EQ(binop->op(), Token::COMMA);
     Expression* left = binop->left();
     Expression* right = binop->right();
-    ParseArrowFunctionFormalParameters(scope, left, params_loc, has_rest,
+    ParseArrowFunctionFormalParameters(parsing_state, left, params_loc,
                                        duplicate_loc, ok);
     if (!*ok) return;
     // LHS of comma expression should be unparenthesized.
@@ -3820,30 +3832,25 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
   }
 
   // Only the right-most expression may be a rest parameter.
-  DCHECK(!*has_rest);
+  DCHECK(!parsing_state->has_rest);
 
+  bool is_rest = false;
   if (expr->IsSpread()) {
-    *has_rest = true;
+    is_rest = true;
     expr = expr->AsSpread()->expression();
   }
 
-  if (!expr->IsVariableProxy()) {
-    // TODO(dslomov): support pattern desugaring
-    return;
+  if (expr->IsVariableProxy()) {
+    // When the formal parameter was originally seen, it was parsed as a
+    // VariableProxy and recorded as unresolved in the scope.  Here we undo that
+    // parse-time side-effect for parameters that are single-names (not
+    // patterns; for patterns that happens uniformly in
+    // PatternRewriter::VisitVariableProxy).
+    parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
   }
-  DCHECK(!expr->AsVariableProxy()->is_this());
-
-  const AstRawString* raw_name = expr->AsVariableProxy()->raw_name();
-  Scanner::Location param_location(expr->position(),
-                                   expr->position() + raw_name->length());
-
-  // When the formal parameter was originally seen, it was parsed as a
-  // VariableProxy and recorded as unresolved in the scope.  Here we undo that
-  // parse-time side-effect.
-  parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
 
   ExpressionClassifier classifier;
-  DeclareFormalParameter(scope, expr, &classifier, *has_rest);
+  DeclareFormalParameter(parsing_state, expr, &classifier, is_rest);
   if (!duplicate_loc->IsValid()) {
     *duplicate_loc = classifier.duplicate_formal_parameter_error().location;
   }
@@ -3918,7 +3925,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
   ZoneList<Statement*>* body = NULL;
   int materialized_literal_count = -1;
   int expected_property_count = -1;
-  ExpressionClassifier formals_classifier;
+  DuplicateFinder duplicate_finder(scanner()->unicode_cache());
+  ExpressionClassifier formals_classifier(&duplicate_finder);
   FunctionLiteral::EagerCompileHint eager_compile_hint =
       parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
                               : FunctionLiteral::kShouldLazyCompile;
@@ -3944,18 +3952,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
       function_state.set_generator_object_variable(temp);
     }
 
-    bool has_rest = false;
     Expect(Token::LPAREN, CHECK_OK);
     int start_position = scanner()->location().beg_pos;
     scope_->set_start_position(start_position);
-    num_parameters = ParseFormalParameterList(scope, &has_rest,
-                                              &formals_classifier, CHECK_OK);
+    ParserFormalParameterParsingState parsing_state(scope);
+    num_parameters =
+        ParseFormalParameterList(&parsing_state, &formals_classifier, CHECK_OK);
     Expect(Token::RPAREN, CHECK_OK);
     int formals_end_position = scanner()->location().end_pos;
 
-    CheckArityRestrictions(num_parameters, arity_restriction, has_rest,
-                           start_position, formals_end_position, CHECK_OK);
-
+    CheckArityRestrictions(num_parameters, arity_restriction,
+                           parsing_state.has_rest, start_position,
+                           formals_end_position, CHECK_OK);
     Expect(Token::LBRACE, CHECK_OK);
 
     // If we have a named function expression, we add a local variable
@@ -4050,8 +4058,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
       }
     }
     if (!is_lazily_parsed) {
-      body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
-                                    kind, CHECK_OK);
+      body = ParseEagerFunctionBody(function_name, pos, parsing_state, fvar,
+                                    fvar_init_op, kind, CHECK_OK);
       materialized_literal_count = function_state.materialized_literal_count();
       expected_property_count = function_state.expected_property_count();
 
@@ -4071,7 +4079,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     CheckFunctionName(language_mode(), kind, function_name,
                       name_is_strict_reserved, function_name_location,
                       CHECK_OK);
-    const bool use_strict_params = has_rest || IsConciseMethod(kind);
+    const bool use_strict_params =
+        !parsing_state.is_simple_parameter_list || IsConciseMethod(kind);
     const bool allow_duplicate_parameters =
         is_sloppy(language_mode()) && !use_strict_params;
     ValidateFormalParameters(&formals_classifier, language_mode(),
@@ -4233,8 +4242,40 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var) {
 }
 
 
+Block* Parser::BuildParameterInitializationBlock(
+    const ParserFormalParameterParsingState& formal_parameters, bool* ok) {
+  DCHECK(scope_->is_function_scope());
+  Block* init_block = nullptr;
+  for (auto parameter : formal_parameters.params) {
+    if (parameter.pattern == nullptr) continue;
+    if (init_block == nullptr) {
+      init_block = factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+    }
+
+    DeclarationDescriptor descriptor;
+    descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
+    descriptor.parser = this;
+    descriptor.declaration_scope = scope_;
+    descriptor.scope = scope_;
+    descriptor.mode = LET;
+    descriptor.is_const = false;
+    descriptor.needs_init = true;
+    descriptor.declaration_pos = parameter.pattern->position();
+    descriptor.initialization_pos = parameter.pattern->position();
+    descriptor.init_op = Token::INIT_LET;
+    DeclarationParsingResult::Declaration decl(
+        parameter.pattern, parameter.pattern->position(),
+        factory()->NewVariableProxy(parameter.var));
+    PatternRewriter::DeclareAndInitializeVariables(init_block, &descriptor,
+                                                   &decl, nullptr, CHECK_OK);
+  }
+  return init_block;
+}
+
+
 ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
-    const AstRawString* function_name, int pos, Variable* fvar,
+    const AstRawString* function_name, int pos,
+    const ParserFormalParameterParsingState& formal_parameters, Variable* fvar,
     Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
   // Everything inside an eagerly parsed function will be parsed eagerly
   // (see comment above).
@@ -4258,6 +4299,12 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
     AddAssertIsConstruct(body, pos);
   }
 
+  auto init_block =
+      BuildParameterInitializationBlock(formal_parameters, CHECK_OK);
+  if (init_block != nullptr) {
+    body->Add(init_block, zone());
+  }
+
   // For generators, allocate and yield an iterator on function entry.
   if (IsGeneratorFunction(kind)) {
     ZoneList<Expression*>* arguments =
@@ -4384,7 +4431,7 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
     Declaration* declaration = factory()->NewVariableDeclaration(
         proxy, CONST, block_scope, pos, is_class_declaration,
         scope_->class_declaration_group_start());
-    Declare(declaration, true, CHECK_OK);
+    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
   }
 
   Expression* extends = NULL;
index 39d0d9278b132fd4dfc5a9ebd104661f1f846205..103bafea3341595f4d08ef58d425567ce037da99 100644 (file)
@@ -538,6 +538,27 @@ class RegExpParser BASE_EMBEDDED {
 class Parser;
 class SingletonLogger;
 
+
+struct ParserFormalParameterParsingState
+    : public PreParserFormalParameterParsingState {
+  struct Parameter {
+    Parameter(Variable* var, Expression* pattern)
+        : var(var), pattern(pattern) {}
+    Variable* var;
+    Expression* pattern;
+  };
+
+  explicit ParserFormalParameterParsingState(Scope* scope)
+      : PreParserFormalParameterParsingState(scope), params(4, scope->zone()) {}
+
+  ZoneList<Parameter> params;
+
+  void AddParameter(Variable* var, Expression* pattern) {
+    params.Add(Parameter(var, pattern), scope->zone());
+  }
+};
+
+
 class ParserTraits {
  public:
   struct Type {
@@ -560,7 +581,7 @@ class ParserTraits {
     typedef ZoneList<v8::internal::Expression*>* ExpressionList;
     typedef ZoneList<ObjectLiteral::Property*>* PropertyList;
     typedef const v8::internal::AstRawString* FormalParameter;
-    typedef Scope FormalParameterScope;
+    typedef ParserFormalParameterParsingState FormalParameterParsingState;
     typedef ZoneList<v8::internal::Statement*>* StatementList;
 
     // For constructing objects returned by the traversing functions.
@@ -751,17 +772,21 @@ class ParserTraits {
   ZoneList<v8::internal::Statement*>* NewStatementList(int size, Zone* zone) {
     return new(zone) ZoneList<v8::internal::Statement*>(size, zone);
   }
+
+  V8_INLINE void AddParameterInitializationBlock(
+      const ParserFormalParameterParsingState& formal_parameters,
+      ZoneList<v8::internal::Statement*>* body, bool* ok);
+
   V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
                             FunctionKind kind = kNormalFunction);
 
-  V8_INLINE void DeclareFormalParameter(Scope* scope, Expression* name,
-                                        ExpressionClassifier* classifier,
-                                        bool is_rest);
-  void ParseArrowFunctionFormalParameters(Scope* scope, Expression* params,
-                                          const Scanner::Location& params_loc,
-                                          bool* has_rest,
-                                          Scanner::Location* duplicate_loc,
-                                          bool* ok);
+  V8_INLINE void DeclareFormalParameter(
+      ParserFormalParameterParsingState* parsing_state, Expression* name,
+      ExpressionClassifier* classifier, bool is_rest);
+  void ParseArrowFunctionFormalParameters(
+      ParserFormalParameterParsingState* scope, Expression* params,
+      const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
+      bool* ok);
 
   // Temporary glue; these functions will move to ParserBase.
   Expression* ParseV8Intrinsic(bool* ok);
@@ -774,8 +799,9 @@ class ParserTraits {
       int* materialized_literal_count, int* expected_property_count, bool* ok,
       Scanner::BookmarkScope* bookmark = nullptr);
   V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
-      const AstRawString* name, int pos, Variable* fvar,
-      Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+      const AstRawString* name, int pos,
+      const ParserFormalParameterParsingState& formal_parameters,
+      Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
 
   ClassLiteral* ParseClassLiteral(const AstRawString* name,
                                   Scanner::Location class_name_location,
@@ -936,6 +962,7 @@ class Parser : public ParserBase<ParserTraits> {
                                 bool* ok);
 
   struct DeclarationDescriptor {
+    enum Kind { NORMAL, PARAMETER };
     Parser* parser;
     Scope* declaration_scope;
     Scope* scope;
@@ -945,6 +972,7 @@ class Parser : public ParserBase<ParserTraits> {
     int declaration_pos;
     int initialization_pos;
     Token::Value init_op;
+    Kind declaration_kind;
   };
 
   struct DeclarationParsingResult {
@@ -1095,7 +1123,9 @@ class Parser : public ParserBase<ParserTraits> {
 
   // Parser support
   VariableProxy* NewUnresolved(const AstRawString* name, VariableMode mode);
-  Variable* Declare(Declaration* declaration, bool resolve, bool* ok);
+  Variable* Declare(Declaration* declaration,
+                    DeclarationDescriptor::Kind declaration_kind, bool resolve,
+                    bool* ok);
 
   bool TargetStackContainsLabel(const AstRawString* label);
   BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
@@ -1121,10 +1151,14 @@ class Parser : public ParserBase<ParserTraits> {
   PreParser::PreParseResult ParseLazyFunctionBodyWithPreParser(
       SingletonLogger* logger, Scanner::BookmarkScope* bookmark = nullptr);
 
+  Block* BuildParameterInitializationBlock(
+      const ParserFormalParameterParsingState& formal_parameters, bool* ok);
+
   // Consumes the ending }.
   ZoneList<Statement*>* ParseEagerFunctionBody(
-      const AstRawString* function_name, int pos, Variable* fvar,
-      Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+      const AstRawString* function_name, int pos,
+      const ParserFormalParameterParsingState& formal_parameters,
+      Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
 
   void ThrowPendingError(Isolate* isolate, Handle<Script> script);
 
@@ -1188,10 +1222,11 @@ void ParserTraits::SkipLazyFunctionBody(int* materialized_literal_count,
 
 
 ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
-    const AstRawString* name, int pos, Variable* fvar,
+    const AstRawString* name, int pos,
+    const ParserFormalParameterParsingState& formal_parameters, Variable* fvar,
     Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
-  return parser_->ParseEagerFunctionBody(name, pos, fvar, fvar_init_op, kind,
-                                         ok);
+  return parser_->ParseEagerFunctionBody(name, pos, formal_parameters, fvar,
+                                         fvar_init_op, kind, ok);
 }
 
 void ParserTraits::CheckConflictingVarDeclarations(v8::internal::Scope* scope,
@@ -1270,18 +1305,20 @@ Expression* ParserTraits::SpreadCallNew(
 }
 
 
-void ParserTraits::DeclareFormalParameter(Scope* scope, Expression* pattern,
-                                          ExpressionClassifier* classifier,
-                                          bool is_rest) {
+void ParserTraits::DeclareFormalParameter(
+    ParserFormalParameterParsingState* parsing_state, Expression* pattern,
+    ExpressionClassifier* classifier, bool is_rest) {
   bool is_duplicate = false;
-  if (!pattern->IsVariableProxy()) {
-    // TODO(dslomov): implement.
-    DCHECK(parser_->allow_harmony_destructuring());
-    return;
-  }
-  auto name = pattern->AsVariableProxy()->raw_name();
-  Variable* var = scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
-  if (is_sloppy(scope->language_mode())) {
+  bool is_simple_name = pattern->IsVariableProxy();
+  DCHECK(parser_->allow_harmony_destructuring() || is_simple_name);
+
+  const AstRawString* name = is_simple_name
+                                 ? pattern->AsVariableProxy()->raw_name()
+                                 : parser_->ast_value_factory()->empty_string();
+  Variable* var =
+      parsing_state->scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
+  parsing_state->AddParameter(var, is_simple_name ? nullptr : pattern);
+  if (is_sloppy(parsing_state->scope->language_mode())) {
     // TODO(sigurds) Mark every parameter as maybe assigned. This is a
     // conservative approximation necessary to account for parameters
     // that are assigned via the arguments array.
@@ -1292,6 +1329,18 @@ void ParserTraits::DeclareFormalParameter(Scope* scope, Expression* pattern,
         parser_->scanner()->location());
   }
 }
+
+
+void ParserTraits::AddParameterInitializationBlock(
+    const ParserFormalParameterParsingState& formal_parameters,
+    ZoneList<v8::internal::Statement*>* body, bool* ok) {
+  auto* init_block =
+      parser_->BuildParameterInitializationBlock(formal_parameters, ok);
+  if (!*ok) return;
+  if (init_block != nullptr) {
+    body->Add(init_block, parser_->zone());
+  }
+}
 } }  // namespace v8::internal
 
 #endif  // V8_PARSER_H_
index a487a10c3597fc51155827b2bacc2a37c050b4a7..6969cf214ed70034fce8f58a737724ab4b600700 100644 (file)
@@ -53,7 +53,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
   Declaration* declaration = factory()->NewVariableDeclaration(
       proxy, descriptor_->mode, descriptor_->scope,
       descriptor_->declaration_pos);
-  Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
+  Variable* var = parser->Declare(declaration, descriptor_->declaration_kind,
+                                  descriptor_->mode != VAR, ok_);
   if (!*ok_) return;
   DCHECK_NOT_NULL(var);
   DCHECK(!proxy->is_resolved() || proxy->var() == var);
index 3a53151399a19f04d65cc5b0258ebc92a5ebc2e4..cfb8a3e3d53525ac0255bbb68e4738ac75185411 100644 (file)
@@ -1038,17 +1038,18 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
   DuplicateFinder duplicate_finder(scanner()->unicode_cache());
   ExpressionClassifier formals_classifier(&duplicate_finder);
 
-  bool has_rest = false;
   Expect(Token::LPAREN, CHECK_OK);
   int start_position = scanner()->location().beg_pos;
   function_scope->set_start_position(start_position);
-  int num_parameters = ParseFormalParameterList(nullptr, &has_rest,
-                                                &formals_classifier, CHECK_OK);
+  PreParserFormalParameterParsingState parsing_state(nullptr);
+  int num_parameters =
+      ParseFormalParameterList(&parsing_state, &formals_classifier, CHECK_OK);
   Expect(Token::RPAREN, CHECK_OK);
   int formals_end_position = scanner()->location().end_pos;
 
-  CheckArityRestrictions(num_parameters, arity_restriction, has_rest,
-                         start_position, formals_end_position, CHECK_OK);
+  CheckArityRestrictions(num_parameters, arity_restriction,
+                         parsing_state.has_rest, start_position,
+                         formals_end_position, CHECK_OK);
 
   // See Parser::ParseFunctionLiteral for more information about lazy parsing
   // and lazy compilation.
@@ -1068,7 +1069,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
   // function, since the function can declare itself strict.
   CheckFunctionName(language_mode(), kind, function_name,
                     name_is_strict_reserved, function_name_location, CHECK_OK);
-  const bool strict_formal_parameters = has_rest || IsConciseMethod(kind);
+  const bool strict_formal_parameters =
+      !parsing_state.is_simple_parameter_list || IsConciseMethod(kind);
   const bool allow_duplicate_parameters =
       is_sloppy(language_mode()) && !strict_formal_parameters;
   ValidateFormalParameters(&formals_classifier, language_mode(),
index ce2c6c429239742a3cca7c4438f377a14c348111..b66053b94697a7d82a59969e1f06a6cd4fd1b3fc 100644 (file)
@@ -70,6 +70,8 @@ class ParserBase : public Traits {
   typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
   typedef typename Traits::Type::Literal LiteralT;
   typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
+  typedef typename Traits::Type::FormalParameterParsingState
+      FormalParameterParsingStateT;
 
   ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
              v8::Extension* extension, AstValueFactory* ast_value_factory,
@@ -557,7 +559,7 @@ class ParserBase : public Traits {
                                      ExpressionT expr, bool* ok) {
     if (classifier->is_valid_binding_pattern()) {
       // A simple arrow formal parameter: IDENTIFIER => BODY.
-      if (!allow_harmony_destructuring() && !this->IsIdentifier(expr)) {
+      if (!this->IsIdentifier(expr)) {
         Traits::ReportMessageAt(scanner()->location(),
                                 MessageTemplate::kUnexpectedToken,
                                 Token::String(scanner()->current_token()));
@@ -646,9 +648,9 @@ class ParserBase : public Traits {
   ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
   ExpressionT ParseMemberExpressionContinuation(
       ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
-  ExpressionT ParseArrowFunctionLiteral(Scope* function_scope, bool has_rest,
-                                        const ExpressionClassifier& classifier,
-                                        bool* ok);
+  ExpressionT ParseArrowFunctionLiteral(
+      const FormalParameterParsingStateT& parsing_state,
+      const ExpressionClassifier& classifier, bool* ok);
   ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
                                    ExpressionClassifier* classifier, bool* ok);
   void AddTemplateExpression(ExpressionT);
@@ -660,9 +662,10 @@ class ParserBase : public Traits {
   ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
                                              bool* ok);
 
-  void ParseFormalParameter(Scope* scope, bool is_rest,
+  void ParseFormalParameter(bool is_rest,
+                            FormalParameterParsingStateT* parsing_result,
                             ExpressionClassifier* classifier, bool* ok);
-  int ParseFormalParameterList(Scope* scope, bool* has_rest,
+  int ParseFormalParameterList(FormalParameterParsingStateT* parsing_state,
                                ExpressionClassifier* classifier, bool* ok);
   void CheckArityRestrictions(
       int param_count, FunctionLiteral::ArityRestriction arity_restriction,
@@ -1254,6 +1257,15 @@ class PreParserFactory {
 };
 
 
+struct PreParserFormalParameterParsingState {
+  explicit PreParserFormalParameterParsingState(Scope* scope)
+      : scope(scope), has_rest(false), is_simple_parameter_list(true) {}
+  Scope* scope;
+  bool has_rest;
+  bool is_simple_parameter_list;
+};
+
+
 class PreParser;
 
 class PreParserTraits {
@@ -1280,6 +1292,7 @@ class PreParserTraits {
     typedef PreParserExpressionList PropertyList;
     typedef PreParserIdentifier FormalParameter;
     typedef PreParserStatementList StatementList;
+    typedef PreParserFormalParameterParsingState FormalParameterParsingState;
 
     // For constructing objects returned by the traversing functions.
     typedef PreParserFactory Factory;
@@ -1518,19 +1531,23 @@ class PreParserTraits {
     return PreParserExpressionList();
   }
 
+  static void AddParameterInitializationBlock(
+      const PreParserFormalParameterParsingState& formal_parameters,
+      PreParserStatementList list, bool* ok) {}
+
   V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
                                       int* expected_property_count, bool* ok) {
     UNREACHABLE();
   }
 
-  V8_INLINE PreParserStatementList
-  ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
-                         Variable* fvar, Token::Value fvar_init_op,
-                         FunctionKind kind, bool* ok);
+  V8_INLINE PreParserStatementList ParseEagerFunctionBody(
+      PreParserIdentifier function_name, int pos,
+      const PreParserFormalParameterParsingState& formal_parameters,
+      Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
 
   V8_INLINE void ParseArrowFunctionFormalParameters(
-      Scope* scope, PreParserExpression expression,
-      const Scanner::Location& params_loc, bool* has_rest,
+      PreParserFormalParameterParsingState* parsing_state,
+      PreParserExpression expression, const Scanner::Location& params_loc,
       Scanner::Location* duplicate_loc, bool* ok);
 
   struct TemplateLiteralState {};
@@ -1557,7 +1574,7 @@ class PreParserTraits {
     return !tag.IsNoTemplateTag();
   }
 
-  void DeclareFormalParameter(Scope* scope, PreParserExpression pattern,
+  void DeclareFormalParameter(void* parsing_state, PreParserExpression pattern,
                               ExpressionClassifier* classifier, bool is_rest) {}
 
   void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
@@ -1708,6 +1725,7 @@ class PreParser : public ParserBase<PreParserTraits> {
                                       int* expected_property_count, bool* ok);
   V8_INLINE PreParserStatementList
   ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
+                         const FormalParameterParsingStateT& formal_parameters,
                          Variable* fvar, Token::Value fvar_init_op,
                          FunctionKind kind, bool* ok);
 
@@ -1753,8 +1771,8 @@ PreParserExpression PreParserTraits::SpreadCallNew(PreParserExpression function,
 
 
 void PreParserTraits::ParseArrowFunctionFormalParameters(
-    Scope* scope, PreParserExpression params,
-    const Scanner::Location& params_loc, bool* has_rest,
+    PreParserFormalParameterParsingState* parsing_state,
+    PreParserExpression params, const Scanner::Location& params_loc,
     Scanner::Location* duplicate_loc, bool* ok) {
   // TODO(wingo): Detect duplicated identifiers in paramlists.  Detect parameter
   // lists that are too long.
@@ -1762,8 +1780,9 @@ void PreParserTraits::ParseArrowFunctionFormalParameters(
 
 
 PreParserStatementList PreParser::ParseEagerFunctionBody(
-    PreParserIdentifier function_name, int pos, Variable* fvar,
-    Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+    PreParserIdentifier function_name, int pos,
+    const PreParserFormalParameterParsingState& formal_parameters,
+    Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
   ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
 
   ParseStatementList(Token::RBRACE, ok);
@@ -1775,10 +1794,11 @@ PreParserStatementList PreParser::ParseEagerFunctionBody(
 
 
 PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
-    PreParserIdentifier function_name, int pos, Variable* fvar,
-    Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
-  return pre_parser_->ParseEagerFunctionBody(function_name, pos, fvar,
-                                             fvar_init_op, kind, ok);
+    PreParserIdentifier function_name, int pos,
+    const PreParserFormalParameterParsingState& formal_parameters,
+    Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+  return pre_parser_->ParseEagerFunctionBody(
+      function_name, pos, formal_parameters, fvar, fvar_init_op, kind, ok);
 }
 
 
@@ -2162,20 +2182,22 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
         }
         Scope* scope =
             this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
+        FormalParameterParsingStateT parsing_state(scope);
         scope->set_start_position(beg_pos);
         ExpressionClassifier args_classifier;
-        bool has_rest = false;
-        result = this->ParseArrowFunctionLiteral(scope, has_rest,
-                                                 args_classifier, CHECK_OK);
+        result = this->ParseArrowFunctionLiteral(parsing_state, args_classifier,
+                                                 CHECK_OK);
       } else if (allow_harmony_arrow_functions() &&
                  allow_harmony_rest_params() && Check(Token::ELLIPSIS)) {
         // (...x) => y
         Scope* scope =
             this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
+        FormalParameterParsingStateT parsing_state(scope);
         scope->set_start_position(beg_pos);
         ExpressionClassifier args_classifier;
-        const bool has_rest = true;
-        this->ParseFormalParameter(scope, has_rest, &args_classifier, CHECK_OK);
+        const bool is_rest = true;
+        this->ParseFormalParameter(is_rest, &parsing_state, &args_classifier,
+                                   CHECK_OK);
         if (peek() == Token::COMMA) {
           ReportMessageAt(scanner()->peek_location(),
                           MessageTemplate::kParamAfterRest);
@@ -2183,8 +2205,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
           return this->EmptyExpression();
         }
         Expect(Token::RPAREN, CHECK_OK);
-        result = this->ParseArrowFunctionLiteral(scope, has_rest,
-                                                 args_classifier, CHECK_OK);
+        result = this->ParseArrowFunctionLiteral(parsing_state, args_classifier,
+                                                 CHECK_OK);
       } else {
         // Heuristically try to detect immediately called functions before
         // seeing the call parentheses.
@@ -2524,6 +2546,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
     DCHECK(!*is_computed_name);
     DCHECK(!is_static);
 
+    if (classifier->duplicate_finder() != nullptr &&
+        scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
+      classifier->RecordDuplicateFormalParameterError(scanner()->location());
+    }
+
     ExpressionT lhs = this->ExpressionFromIdentifier(
         name, next_beg_pos, next_end_pos, scope_, factory());
     if (peek() == Token::ASSIGN) {
@@ -2707,7 +2734,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
 
   if (fni_ != NULL) fni_->Enter();
   ParserBase<Traits>::Checkpoint checkpoint(this);
-  ExpressionClassifier arrow_formals_classifier;
+  ExpressionClassifier arrow_formals_classifier(classifier->duplicate_finder());
   if (peek() != Token::LPAREN) {
     // The expression we are going to read is not a parenthesized arrow function
     // formal parameter list.
@@ -2726,15 +2753,15 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
         this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
     scope->set_start_position(lhs_location.beg_pos);
     Scanner::Location duplicate_loc = Scanner::Location::invalid();
-    bool has_rest = false;
-    this->ParseArrowFunctionFormalParameters(scope, expression, loc, &has_rest,
+    FormalParameterParsingStateT parsing_state(scope);
+    this->ParseArrowFunctionFormalParameters(&parsing_state, expression, loc,
                                              &duplicate_loc, CHECK_OK);
     if (duplicate_loc.IsValid()) {
       arrow_formals_classifier.RecordDuplicateFormalParameterError(
           duplicate_loc);
     }
     expression = this->ParseArrowFunctionLiteral(
-        scope, has_rest, arrow_formals_classifier, CHECK_OK);
+        parsing_state, arrow_formals_classifier, CHECK_OK);
     return expression;
   }
 
@@ -3497,9 +3524,9 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
 
 
 template <class Traits>
-void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest,
-                                              ExpressionClassifier* classifier,
-                                              bool* ok) {
+void ParserBase<Traits>::ParseFormalParameter(
+    bool is_rest, FormalParameterParsingStateT* parsing_state,
+    ExpressionClassifier* classifier, bool* ok) {
   // FormalParameter[Yield,GeneratorParameter] :
   //   BindingElement[?Yield, ?GeneratorParameter]
 
@@ -3516,13 +3543,24 @@ void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest,
     return;
   }
 
-  Traits::DeclareFormalParameter(scope, pattern, classifier, is_rest);
+  if (parsing_state->is_simple_parameter_list) {
+    parsing_state->is_simple_parameter_list =
+        !is_rest && Traits::IsIdentifier(pattern);
+  }
+  parsing_state->has_rest = is_rest;
+  if (is_rest && !Traits::IsIdentifier(pattern)) {
+    ReportUnexpectedToken(next);
+    *ok = false;
+    return;
+  }
+  Traits::DeclareFormalParameter(parsing_state, pattern, classifier, is_rest);
 }
 
 
 template <class Traits>
 int ParserBase<Traits>::ParseFormalParameterList(
-    Scope* scope, bool* is_rest, ExpressionClassifier* classifier, bool* ok) {
+    FormalParameterParsingStateT* parsing_state,
+    ExpressionClassifier* classifier, bool* ok) {
   // FormalParameters[Yield,GeneratorParameter] :
   //   [empty]
   //   FormalParameterList[?Yield, ?GeneratorParameter]
@@ -3546,12 +3584,12 @@ int ParserBase<Traits>::ParseFormalParameterList(
         *ok = false;
         return -1;
       }
-      *is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS);
-      ParseFormalParameter(scope, *is_rest, classifier, ok);
+      bool is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS);
+      ParseFormalParameter(is_rest, parsing_state, classifier, ok);
       if (!*ok) return -1;
-    } while (!*is_rest && Check(Token::COMMA));
+    } while (!parsing_state->has_rest && Check(Token::COMMA));
 
-    if (*is_rest && peek() == Token::COMMA) {
+    if (parsing_state->has_rest && peek() == Token::COMMA) {
       ReportMessageAt(scanner()->peek_location(),
                       MessageTemplate::kParamAfterRest);
       *ok = false;
@@ -3596,8 +3634,8 @@ void ParserBase<Traits>::CheckArityRestrictions(
 template <class Traits>
 typename ParserBase<Traits>::ExpressionT
 ParserBase<Traits>::ParseArrowFunctionLiteral(
-    Scope* scope, bool has_rest, const ExpressionClassifier& formals_classifier,
-    bool* ok) {
+    const FormalParameterParsingStateT& formal_parameters,
+    const ExpressionClassifier& formals_classifier, bool* ok) {
   if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
     // ASI inserts `;` after arrow parameters if a line terminator is found.
     // `=> ...` is never a valid expression, so report as syntax error.
@@ -3608,15 +3646,16 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
   }
 
   typename Traits::Type::StatementList body;
-  int num_parameters = scope->num_parameters();
+  int num_parameters = formal_parameters.scope->num_parameters();
   int materialized_literal_count = -1;
   int expected_property_count = -1;
   Scanner::Location super_loc;
 
   {
     typename Traits::Type::Factory function_factory(ast_value_factory());
-    FunctionState function_state(&function_state_, &scope_, scope,
-                                 kArrowFunction, &function_factory);
+    FunctionState function_state(&function_state_, &scope_,
+                                 formal_parameters.scope, kArrowFunction,
+                                 &function_factory);
 
     Expect(Token::ARROW, CHECK_OK);
 
@@ -3631,8 +3670,8 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
                                    &expected_property_count, CHECK_OK);
       } else {
         body = this->ParseEagerFunctionBody(
-            this->EmptyIdentifier(), RelocInfo::kNoPosition, NULL,
-            Token::INIT_VAR, kArrowFunction, CHECK_OK);
+            this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
+            NULL, Token::INIT_VAR, kArrowFunction, CHECK_OK);
         materialized_literal_count =
             function_state.materialized_literal_count();
         expected_property_count = function_state.expected_property_count();
@@ -3646,13 +3685,14 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
           ParseAssignmentExpression(true, &classifier, CHECK_OK);
       ValidateExpression(&classifier, CHECK_OK);
       body = this->NewStatementList(1, zone());
+      this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
       body->Add(factory()->NewReturnStatement(expression, pos), zone());
       materialized_literal_count = function_state.materialized_literal_count();
       expected_property_count = function_state.expected_property_count();
     }
     super_loc = function_state.super_location();
 
-    scope->set_end_position(scanner()->location().end_pos);
+    formal_parameters.scope->set_end_position(scanner()->location().end_pos);
 
     // Arrow function formal parameters are parsed as StrictFormalParameterList,
     // which is not the same as "parameters of a strict function"; it only means
@@ -3664,21 +3704,23 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
 
     // Validate strict mode.
     if (is_strict(language_mode())) {
-      CheckStrictOctalLiteral(scope->start_position(),
+      CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
                               scanner()->location().end_pos, CHECK_OK);
-      this->CheckConflictingVarDeclarations(scope, CHECK_OK);
+      this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
     }
   }
 
   FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
-      this->EmptyIdentifierString(), ast_value_factory(), scope, body,
-      materialized_literal_count, expected_property_count, num_parameters,
+      this->EmptyIdentifierString(), ast_value_factory(),
+      formal_parameters.scope, body, materialized_literal_count,
+      expected_property_count, num_parameters,
       FunctionLiteral::kNoDuplicateParameters,
       FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction,
       FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
-      scope->start_position());
+      formal_parameters.scope->start_position());
 
-  function_literal->set_function_token_position(scope->start_position());
+  function_literal->set_function_token_position(
+      formal_parameters.scope->start_position());
   if (super_loc.IsValid()) function_state_->set_super_location(super_loc);
 
   if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
index 039bea0987a4261432cab324cdd464e0e87939a6..61a75ab16fcf408a0ba79355f4e43d59979564c8 100644 (file)
@@ -466,15 +466,22 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode,
                                   bool is_rest, bool* is_duplicate) {
   DCHECK(!already_resolved());
   DCHECK(is_function_scope());
-  Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL,
-                                     kCreatedInitialized);
+
+  Variable* var;
+  if (!name->IsEmpty()) {
+    var = variables_.Declare(this, name, mode, Variable::NORMAL,
+                             kCreatedInitialized);
+    // TODO(wingo): Avoid O(n^2) check.
+    *is_duplicate = IsDeclaredParameter(name);
+  } else {
+    var = new (zone())
+        Variable(this, name, TEMPORARY, Variable::NORMAL, kCreatedInitialized);
+  }
   if (is_rest) {
     DCHECK_NULL(rest_parameter_);
     rest_parameter_ = var;
     rest_index_ = num_parameters();
   }
-  // TODO(wingo): Avoid O(n^2) check.
-  *is_duplicate = IsDeclaredParameter(name);
   params_.Add(var, zone());
   return var;
 }
index 675b48797952dbaf3e0afd23b933c61651ea1998..1aa520183d21749f14f529077dbee86a9dbf5f71 100644 (file)
@@ -6389,7 +6389,6 @@ TEST(DestructuringPositiveTests) {
                                    {"function f(", ") {}"},
                                    {"function f(argument1, ", ") {}"},
                                    {"var f = (", ") => {};"},
-                                   {"var f = ", " => {};"},
                                    {"var f = (argument1,", ") => {};"},
                                    {NULL, NULL}};
 
@@ -6417,6 +6416,7 @@ TEST(DestructuringPositiveTests) {
     "{42 : x = 42}",
     "{42e-2 : x}",
     "{42e-2 : x = 42}",
+    "{x : y, x : z}",
     "{'hi' : x}",
     "{'hi' : x = 42}",
     "{var: x}",
@@ -6605,6 +6605,115 @@ TEST(DestructuringDisallowPatternsInForVarIn) {
 }
 
 
+TEST(DestructuringDuplicateParams) {
+  i::FLAG_harmony_destructuring = true;
+  i::FLAG_harmony_arrow_functions = true;
+  i::FLAG_harmony_computed_property_names = true;
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+      kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function outer() { 'use strict';", "}"},
+                                   {nullptr, nullptr}};
+
+
+  // clang-format off
+  const char* error_data[] = {
+    "function f(x,x){}",
+    "function f(x, {x : x}){}",
+    "function f(x, {x}){}",
+    "function f({x,x}) {}",
+    "function f([x,x]) {}",
+    "function f(x, [y,{z:x}]) {}",
+    "function f([x,{y:x}]) {}",
+    // non-simple parameter list causes duplicates to be errors in sloppy mode.
+    "function f(x, x, {a}) {}",
+    nullptr};
+  // clang-format on
+  RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(DestructuringDuplicateParamsSloppy) {
+  i::FLAG_harmony_destructuring = true;
+  i::FLAG_harmony_arrow_functions = true;
+  i::FLAG_harmony_computed_property_names = true;
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+      kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
+  const char* context_data[][2] = {
+      {"", ""}, {"function outer() {", "}"}, {nullptr, nullptr}};
+
+
+  // clang-format off
+  const char* error_data[] = {
+    // non-simple parameter list causes duplicates to be errors in sloppy mode.
+    "function f(x, {x : x}){}",
+    "function f(x, {x}){}",
+    "function f({x,x}) {}",
+    "function f(x, x, {a}) {}",
+    nullptr};
+  // clang-format on
+  RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(DestructuringDisallowPatternsInSingleParamArrows) {
+  i::FLAG_harmony_destructuring = true;
+  i::FLAG_harmony_arrow_functions = true;
+  i::FLAG_harmony_computed_property_names = true;
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+      kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function outer() { 'use strict';", "}"},
+                                   {"", ""},
+                                   {"function outer() { ", "}"},
+                                   {nullptr, nullptr}};
+
+  // clang-format off
+  const char* error_data[] = {
+    "var f = {x} => {};",
+    "var f = {x,y} => {};",
+    nullptr};
+  // clang-format on
+  RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(DestructuringDisallowPatternsInRestParams) {
+  i::FLAG_harmony_destructuring = true;
+  i::FLAG_harmony_arrow_functions = true;
+  i::FLAG_harmony_rest_parameters = true;
+  i::FLAG_harmony_computed_property_names = true;
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+      kAllowHarmonyArrowFunctions, kAllowHarmonyRestParameters,
+      kAllowHarmonyDestructuring};
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function outer() { 'use strict';", "}"},
+                                   {"", ""},
+                                   {"function outer() { ", "}"},
+                                   {nullptr, nullptr}};
+
+  // clang-format off
+  const char* error_data[] = {
+    "function(...{}) {}",
+    "function(...{x}) {}",
+    "function(...[x]) {}",
+    "(...{}) => {}",
+    "(...{x}) => {}",
+    "(...[x]) => {}",
+    nullptr};
+  // clang-format on
+  RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
 TEST(SpreadArray) {
   i::FLAG_harmony_spread_arrays = true;
 
index 731bc6dbe5c6c3a1b9fc10e80dcde7371c16bfb6..c57dbafda6dbbd90862b11bd6af10e986e7bc2eb 100644 (file)
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 //
 // Flags: --harmony-destructuring --harmony-computed-property-names
+// Flags: --harmony-arrow-functions
 
 (function TestObjectLiteralPattern() {
   var { x : x, y : y } = { x : 1, y : 2 };
   assertEquals('ab', sx);
   assertEquals('12', sy);
 }());
+
+
+(function TestParameters() {
+  function f({a, b}) { return a - b; }
+  assertEquals(1, f({a : 6, b : 5}));
+
+  function f1(c, {a, b}) { return c + a - b; }
+  assertEquals(8, f1(7, {a : 6, b : 5}));
+
+  function f2({c, d}, {a, b}) { return c - d + a - b; }
+  assertEquals(7, f2({c : 7, d : 1}, {a : 6, b : 5}));
+
+  function f3([{a, b}]) { return a - b; }
+  assertEquals(1, f3([{a : 6, b : 5}]));
+
+  var g = ({a, b}) => { return a - b; };
+  assertEquals(1, g({a : 6, b : 5}));
+
+  var g1 = (c, {a, b}) => { return c + a - b; };
+  assertEquals(8, g1(7, {a : 6, b : 5}));
+
+  var g2 = ({c, d}, {a, b}) => { return c - d + a - b; };
+  assertEquals(7, g2({c : 7, d : 1}, {a : 6, b : 5}));
+
+  var g3 = ([{a, b}]) => { return a - b; };
+  assertEquals(1, g3([{a : 6, b : 5}]));
+}());
+
+
+(function TestDuplicatesInParameters() {
+  assertThrows("'use strict';function f(x,x){}", SyntaxError);
+  assertThrows("'use strict';function f({x,x}){}", SyntaxError);
+  assertThrows("'use strict';function f(x, {x}){}", SyntaxError);
+  assertThrows("'use strict';var f = (x,x) => {};", SyntaxError);
+  assertThrows("'use strict';var f = ({x,x}) => {};", SyntaxError);
+  assertThrows("'use strict';var f = (x, {x}) => {};", SyntaxError);
+
+  function ok(x) { var x; }; ok();
+  assertThrows("function f({x}) { var x; }; f({});", SyntaxError);
+  assertThrows("'use strict'; function f({x}) { let x = 0; }; f({});", SyntaxError);
+}());
index 07d5e3d46727e4f8fef105dd895f205d33200a56..6ba430b04f28cbaf45e37f91f4a05d918e0d83ec 100644 (file)
@@ -35,6 +35,6 @@ try {
   eval("(function() { const x; var x })")();
 } catch (e) {
   exception = true;
-  assertTrue(e instanceof TypeError);
+  assertTrue(e instanceof SyntaxError);
 }
 assertTrue(exception);
index 344a7a3049305a655b74f0ca56ea5ecba3bbf58c..0ea70523fe3523d650fafb5206971ebb2fdc7f65 100644 (file)
@@ -14,4 +14,4 @@ function g(x) {
 }
 
 %OptimizeFunctionOnNextCall(g);
-assertThrows(function() { g(42); }, TypeError);
+assertThrows(function() { g(42); }, SyntaxError);
index f5bbb729368a34e8648079d999ce47b29a252ab9..4f0150033df39eeec4f8213bdc6e8b39eb854d40 100644 (file)
@@ -157,7 +157,7 @@ PASS access_after_delete_extra_5(1, 2, 3, 4, 5) is 5
 PASS argumentsParam(true) is true
 PASS argumentsFunctionConstructorParam(true) is true
 PASS argumentsVarUndefined() is '[object Arguments]'
-FAIL argumentsConstUndefined() should be [object Arguments]. Threw exception TypeError: Identifier 'arguments' has already been declared
+FAIL argumentsConstUndefined() should be [object Arguments]. Threw exception SyntaxError: Identifier 'arguments' has already been declared
 PASS argumentCalleeInException() is argumentCalleeInException
 PASS shadowedArgumentsApply([true]) is true
 PASS shadowedArgumentsLength([]) is 0