Commit 55e1cfeb authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

[parser] early error when declaration Pattern missing Initializer

Emit an early error when BindingPatterns are used in a VariableDeclaration
or LexicalBinding without an Initializer.

BUG=v8:4532
LOG=N
R=adamk@chromium.org, rossberg@chromium.org, wingo@igalia.com

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

Cr-Commit-Position: refs/heads/master@{#31802}
parent a77aa3a2
...@@ -108,6 +108,7 @@ class CallSite { ...@@ -108,6 +108,7 @@ class CallSite {
T(DateType, "this is not a Date object.") \ T(DateType, "this is not a Date object.") \
T(DebuggerFrame, "Debugger: Invalid frame index.") \ T(DebuggerFrame, "Debugger: Invalid frame index.") \
T(DebuggerType, "Debugger: Parameters have wrong types.") \ T(DebuggerType, "Debugger: Parameters have wrong types.") \
T(DeclarationMissingInitializer, "Missing initializer in % declaration") \
T(DefineDisallowed, "Cannot define property:%, object is not extensible.") \ T(DefineDisallowed, "Cannot define property:%, object is not extensible.") \
T(DuplicateTemplateProperty, "Object template has duplicate property '%'") \ T(DuplicateTemplateProperty, "Object template has duplicate property '%'") \
T(ExtendsValueGenerator, \ T(ExtendsValueGenerator, \
......
...@@ -2531,6 +2531,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2531,6 +2531,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
if (!first_declaration) Consume(Token::COMMA); if (!first_declaration) Consume(Token::COMMA);
Expression* pattern; Expression* pattern;
int decl_pos = peek_position();
{ {
ExpressionClassifier pattern_classifier; ExpressionClassifier pattern_classifier;
Token::Value next = peek(); Token::Value next = peek();
...@@ -2549,6 +2550,8 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2549,6 +2550,8 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
} }
} }
bool is_pattern = pattern->IsObjectLiteral() || pattern->IsArrayLiteral();
Scanner::Location variable_loc = scanner()->location(); Scanner::Location variable_loc = scanner()->location();
const AstRawString* single_name = const AstRawString* single_name =
pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name() pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name()
...@@ -2569,10 +2572,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2569,10 +2572,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Expression* value = NULL; Expression* value = NULL;
// Harmony consts have non-optional initializers. // Harmony consts have non-optional initializers.
int initializer_position = RelocInfo::kNoPosition; int initializer_position = RelocInfo::kNoPosition;
if (peek() == Token::ASSIGN || (parsing_result->descriptor.mode == CONST && if (Check(Token::ASSIGN)) {
!is_for_iteration_variable)) {
Expect(Token::ASSIGN, ok);
if (!*ok) return;
ExpressionClassifier classifier; ExpressionClassifier classifier;
value = ParseAssignmentExpression(var_context != kForStatement, value = ParseAssignmentExpression(var_context != kForStatement,
&classifier, ok); &classifier, ok);
...@@ -2597,6 +2597,15 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2597,6 +2597,15 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// End position of the initializer is after the assignment expression. // End position of the initializer is after the assignment expression.
initializer_position = scanner()->location().end_pos; initializer_position = scanner()->location().end_pos;
} else { } else {
if ((parsing_result->descriptor.mode == CONST || is_pattern) &&
!is_for_iteration_variable) {
ParserTraits::ReportMessageAt(
Scanner::Location(decl_pos, scanner()->location().end_pos),
MessageTemplate::kDeclarationMissingInitializer,
is_pattern ? "destructuring" : "const");
*ok = false;
return;
}
// End position of the initializer is after the variable. // End position of the initializer is after the variable.
initializer_position = position(); initializer_position = position();
} }
......
...@@ -532,7 +532,6 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -532,7 +532,6 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
// ConstBinding :: // ConstBinding ::
// BindingPattern '=' AssignmentExpression // BindingPattern '=' AssignmentExpression
bool require_initializer = false; bool require_initializer = false;
bool is_strict_const = false;
bool lexical = false; bool lexical = false;
if (peek() == Token::VAR) { if (peek() == Token::VAR) {
if (is_strong(language_mode())) { if (is_strong(language_mode())) {
...@@ -557,8 +556,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -557,8 +556,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
if (is_strict(language_mode()) || if (is_strict(language_mode()) ||
(allow_harmony_sloppy() && !allow_legacy_const())) { (allow_harmony_sloppy() && !allow_legacy_const())) {
DCHECK(var_context != kStatement); DCHECK(var_context != kStatement);
is_strict_const = true; require_initializer = true;
require_initializer = var_context != kForStatement;
lexical = true; lexical = true;
} }
} else if (peek() == Token::LET && allow_let()) { } else if (peek() == Token::LET && allow_let()) {
...@@ -579,11 +577,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -579,11 +577,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
do { do {
// Parse binding pattern. // Parse binding pattern.
if (nvars > 0) Consume(Token::COMMA); if (nvars > 0) Consume(Token::COMMA);
int decl_pos = peek_position();
PreParserExpression pattern = PreParserExpression::Default();
{ {
ExpressionClassifier pattern_classifier; ExpressionClassifier pattern_classifier;
Token::Value next = peek(); Token::Value next = peek();
PreParserExpression pattern = pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK); ValidateBindingPattern(&pattern_classifier, CHECK_OK);
if (lexical) { if (lexical) {
ValidateLetPattern(&pattern_classifier, CHECK_OK); ValidateLetPattern(&pattern_classifier, CHECK_OK);
...@@ -596,12 +596,15 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -596,12 +596,15 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
} }
} }
bool is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral();
bool is_for_iteration_variable =
var_context == kForStatement &&
(peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
Scanner::Location variable_loc = scanner()->location(); Scanner::Location variable_loc = scanner()->location();
nvars++; nvars++;
if (peek() == Token::ASSIGN || require_initializer || if (Check(Token::ASSIGN)) {
// require initializers for multiple consts.
(is_strict_const && peek() == Token::COMMA)) {
Expect(Token::ASSIGN, CHECK_OK);
ExpressionClassifier classifier; ExpressionClassifier classifier;
ParseAssignmentExpression(var_context != kForStatement, &classifier, ParseAssignmentExpression(var_context != kForStatement, &classifier,
CHECK_OK); CHECK_OK);
...@@ -611,6 +614,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -611,6 +614,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
if (first_initializer_loc && !first_initializer_loc->IsValid()) { if (first_initializer_loc && !first_initializer_loc->IsValid()) {
*first_initializer_loc = variable_loc; *first_initializer_loc = variable_loc;
} }
} else if ((require_initializer || is_pattern) &&
!is_for_iteration_variable) {
PreParserTraits::ReportMessageAt(
Scanner::Location(decl_pos, scanner()->location().end_pos),
MessageTemplate::kDeclarationMissingInitializer,
is_pattern ? "destructuring" : "const");
*ok = false;
return Statement::Default();
} }
} while (peek() == Token::COMMA); } while (peek() == Token::COMMA);
......
...@@ -948,6 +948,14 @@ class PreParserExpression { ...@@ -948,6 +948,14 @@ class PreParserExpression {
right->IsSpreadExpression())); right->IsSpreadExpression()));
} }
static PreParserExpression ObjectLiteral() {
return PreParserExpression(TypeField::encode(kObjectLiteralExpression));
}
static PreParserExpression ArrayLiteral() {
return PreParserExpression(TypeField::encode(kArrayLiteralExpression));
}
static PreParserExpression StringLiteral() { static PreParserExpression StringLiteral() {
return PreParserExpression(TypeField::encode(kStringLiteralExpression)); return PreParserExpression(TypeField::encode(kStringLiteralExpression));
} }
...@@ -1005,6 +1013,14 @@ class PreParserExpression { ...@@ -1005,6 +1013,14 @@ class PreParserExpression {
return PreParserIdentifier(IdentifierTypeField::decode(code_)); return PreParserIdentifier(IdentifierTypeField::decode(code_));
} }
bool IsObjectLiteral() const {
return TypeField::decode(code_) == kObjectLiteralExpression;
}
bool IsArrayLiteral() const {
return TypeField::decode(code_) == kArrayLiteralExpression;
}
bool IsStringLiteral() const { bool IsStringLiteral() const {
return TypeField::decode(code_) == kStringLiteralExpression; return TypeField::decode(code_) == kStringLiteralExpression;
} }
...@@ -1093,7 +1109,9 @@ class PreParserExpression { ...@@ -1093,7 +1109,9 @@ class PreParserExpression {
kIdentifierExpression, kIdentifierExpression,
kStringLiteralExpression, kStringLiteralExpression,
kBinaryOperationExpression, kBinaryOperationExpression,
kSpreadExpression kSpreadExpression,
kObjectLiteralExpression,
kArrayLiteralExpression
}; };
enum ExpressionType { enum ExpressionType {
...@@ -1231,12 +1249,12 @@ class PreParserFactory { ...@@ -1231,12 +1249,12 @@ class PreParserFactory {
int literal_index, int literal_index,
bool is_strong, bool is_strong,
int pos) { int pos) {
return PreParserExpression::Default(); return PreParserExpression::ArrayLiteral();
} }
PreParserExpression NewArrayLiteral(PreParserExpressionList values, PreParserExpression NewArrayLiteral(PreParserExpressionList values,
int first_spread_index, int literal_index, int first_spread_index, int literal_index,
bool is_strong, int pos) { bool is_strong, int pos) {
return PreParserExpression::Default(); return PreParserExpression::ArrayLiteral();
} }
PreParserExpression NewObjectLiteralProperty(PreParserExpression key, PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
PreParserExpression value, PreParserExpression value,
...@@ -1257,7 +1275,7 @@ class PreParserFactory { ...@@ -1257,7 +1275,7 @@ class PreParserFactory {
bool has_function, bool has_function,
bool is_strong, bool is_strong,
int pos) { int pos) {
return PreParserExpression::Default(); return PreParserExpression::ObjectLiteral();
} }
PreParserExpression NewVariableProxy(void* variable) { PreParserExpression NewVariableProxy(void* variable) {
return PreParserExpression::Default(); return PreParserExpression::Default();
......
...@@ -6702,6 +6702,33 @@ TEST(DestructuringNegativeTests) { ...@@ -6702,6 +6702,33 @@ TEST(DestructuringNegativeTests) {
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags)); arraysize(always_flags));
} }
{ // Declaration-specific errors
const char* context_data[][2] = {{"'use strict'; var ", ""},
{"'use strict'; let ", ""},
{"'use strict'; const ", ""},
{"'use strict'; for (var ", ";;) {}"},
{"'use strict'; for (let ", ";;) {}"},
{"'use strict'; for (const ", ";;) {}"},
{"var ", ""},
{"let ", ""},
{"const ", ""},
{"for (var ", ";;) {}"},
{"for (let ", ";;) {}"},
{"for (const ", ";;) {}"},
{NULL, NULL}};
// clang-format off
const char* data[] = {
"{ a }",
"[ a ]",
NULL};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring,
kAllowHarmonySloppyLet};
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
} }
...@@ -7188,13 +7215,13 @@ TEST(LetSloppyOnly) { ...@@ -7188,13 +7215,13 @@ TEST(LetSloppyOnly) {
"for (var [let] = 1; let < 1; let++) {}", "for (var [let] = 1; let < 1; let++) {}",
"for (var [let] in {}) {}", "for (var [let] in {}) {}",
"var let", "var let",
"var [let]", "var [let] = []",
"for (const let = 1; let < 1; let++) {}", "for (const let = 1; let < 1; let++) {}",
"for (const let in {}) {}", "for (const let in {}) {}",
"for (const [let] = 1; let < 1; let++) {}", "for (const [let] = 1; let < 1; let++) {}",
"for (const [let] in {}) {}", "for (const [let] in {}) {}",
"const let", "const let",
"const [let]", "const [let] = []",
NULL NULL
}; };
// clang-format on // clang-format on
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
const a;
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:6: SyntaxError: Missing initializer in const declaration
const a;
^
SyntaxError: Missing initializer in const declaration
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
for (const a; ;) {}
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:6: SyntaxError: Missing initializer in const declaration
for (const a; ;) {}
^
SyntaxError: Missing initializer in const declaration
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-destructuring
var [ a, b, c ];
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:7: SyntaxError: Missing initializer in destructuring declaration
var [ a, b, c ];
^^^^^^^^^^^
SyntaxError: Missing initializer in destructuring declaration
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-destructuring
for (var [ a ]; a; ) {}
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:7: SyntaxError: Missing initializer in destructuring declaration
for (var [ a ]; a; ) {}
^^^^^
SyntaxError: Missing initializer in destructuring declaration
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-destructuring
var { a, b, c };
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:7: SyntaxError: Missing initializer in destructuring declaration
var { a, b, c };
^^^^^^^^^^^
SyntaxError: Missing initializer in destructuring declaration
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-destructuring
for (var { a, b, c }; a && b && c; ) {}
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:7: SyntaxError: Missing initializer in destructuring declaration
for (var { a, b, c }; a && b && c; ) {}
^^^^^^^^^^^
SyntaxError: Missing initializer in destructuring declaration
...@@ -1103,7 +1103,3 @@ ...@@ -1103,7 +1103,3 @@
for (const {foo} of [{foo: 1}]) { result = foo; } for (const {foo} of [{foo: 1}]) { result = foo; }
assertEquals(1, result); assertEquals(1, result);
})(); })();
(function TestDestructuringArrayWithoutInitializer() {
assertThrows('var [foo]', TypeError);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment