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 {
T(DateType, "this is not a Date object.") \
T(DebuggerFrame, "Debugger: Invalid frame index.") \
T(DebuggerType, "Debugger: Parameters have wrong types.") \
T(DeclarationMissingInitializer, "Missing initializer in % declaration") \
T(DefineDisallowed, "Cannot define property:%, object is not extensible.") \
T(DuplicateTemplateProperty, "Object template has duplicate property '%'") \
T(ExtendsValueGenerator, \
......
......@@ -2531,6 +2531,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
if (!first_declaration) Consume(Token::COMMA);
Expression* pattern;
int decl_pos = peek_position();
{
ExpressionClassifier pattern_classifier;
Token::Value next = peek();
......@@ -2549,6 +2550,8 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
}
}
bool is_pattern = pattern->IsObjectLiteral() || pattern->IsArrayLiteral();
Scanner::Location variable_loc = scanner()->location();
const AstRawString* single_name =
pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name()
......@@ -2569,10 +2572,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Expression* value = NULL;
// Harmony consts have non-optional initializers.
int initializer_position = RelocInfo::kNoPosition;
if (peek() == Token::ASSIGN || (parsing_result->descriptor.mode == CONST &&
!is_for_iteration_variable)) {
Expect(Token::ASSIGN, ok);
if (!*ok) return;
if (Check(Token::ASSIGN)) {
ExpressionClassifier classifier;
value = ParseAssignmentExpression(var_context != kForStatement,
&classifier, ok);
......@@ -2597,6 +2597,15 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// End position of the initializer is after the assignment expression.
initializer_position = scanner()->location().end_pos;
} 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.
initializer_position = position();
}
......
......@@ -532,7 +532,6 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
// ConstBinding ::
// BindingPattern '=' AssignmentExpression
bool require_initializer = false;
bool is_strict_const = false;
bool lexical = false;
if (peek() == Token::VAR) {
if (is_strong(language_mode())) {
......@@ -557,8 +556,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
if (is_strict(language_mode()) ||
(allow_harmony_sloppy() && !allow_legacy_const())) {
DCHECK(var_context != kStatement);
is_strict_const = true;
require_initializer = var_context != kForStatement;
require_initializer = true;
lexical = true;
}
} else if (peek() == Token::LET && allow_let()) {
......@@ -579,11 +577,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
do {
// Parse binding pattern.
if (nvars > 0) Consume(Token::COMMA);
int decl_pos = peek_position();
PreParserExpression pattern = PreParserExpression::Default();
{
ExpressionClassifier pattern_classifier;
Token::Value next = peek();
PreParserExpression pattern =
ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
if (lexical) {
ValidateLetPattern(&pattern_classifier, CHECK_OK);
......@@ -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();
nvars++;
if (peek() == Token::ASSIGN || require_initializer ||
// require initializers for multiple consts.
(is_strict_const && peek() == Token::COMMA)) {
Expect(Token::ASSIGN, CHECK_OK);
if (Check(Token::ASSIGN)) {
ExpressionClassifier classifier;
ParseAssignmentExpression(var_context != kForStatement, &classifier,
CHECK_OK);
......@@ -611,6 +614,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
if (first_initializer_loc && !first_initializer_loc->IsValid()) {
*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);
......
......@@ -948,6 +948,14 @@ class PreParserExpression {
right->IsSpreadExpression()));
}
static PreParserExpression ObjectLiteral() {
return PreParserExpression(TypeField::encode(kObjectLiteralExpression));
}
static PreParserExpression ArrayLiteral() {
return PreParserExpression(TypeField::encode(kArrayLiteralExpression));
}
static PreParserExpression StringLiteral() {
return PreParserExpression(TypeField::encode(kStringLiteralExpression));
}
......@@ -1005,6 +1013,14 @@ class PreParserExpression {
return PreParserIdentifier(IdentifierTypeField::decode(code_));
}
bool IsObjectLiteral() const {
return TypeField::decode(code_) == kObjectLiteralExpression;
}
bool IsArrayLiteral() const {
return TypeField::decode(code_) == kArrayLiteralExpression;
}
bool IsStringLiteral() const {
return TypeField::decode(code_) == kStringLiteralExpression;
}
......@@ -1093,7 +1109,9 @@ class PreParserExpression {
kIdentifierExpression,
kStringLiteralExpression,
kBinaryOperationExpression,
kSpreadExpression
kSpreadExpression,
kObjectLiteralExpression,
kArrayLiteralExpression
};
enum ExpressionType {
......@@ -1231,12 +1249,12 @@ class PreParserFactory {
int literal_index,
bool is_strong,
int pos) {
return PreParserExpression::Default();
return PreParserExpression::ArrayLiteral();
}
PreParserExpression NewArrayLiteral(PreParserExpressionList values,
int first_spread_index, int literal_index,
bool is_strong, int pos) {
return PreParserExpression::Default();
return PreParserExpression::ArrayLiteral();
}
PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
PreParserExpression value,
......@@ -1257,7 +1275,7 @@ class PreParserFactory {
bool has_function,
bool is_strong,
int pos) {
return PreParserExpression::Default();
return PreParserExpression::ObjectLiteral();
}
PreParserExpression NewVariableProxy(void* variable) {
return PreParserExpression::Default();
......
......@@ -6702,6 +6702,33 @@ TEST(DestructuringNegativeTests) {
RunParserSyncTest(context_data, data, kError, NULL, 0, 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) {
"for (var [let] = 1; let < 1; let++) {}",
"for (var [let] in {}) {}",
"var let",
"var [let]",
"var [let] = []",
"for (const let = 1; let < 1; let++) {}",
"for (const let in {}) {}",
"for (const [let] = 1; let < 1; let++) {}",
"for (const [let] in {}) {}",
"const let",
"const [let]",
"const [let] = []",
NULL
};
// 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 @@
for (const {foo} of [{foo: 1}]) { result = foo; }
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