[parser] Allow duplicate __proto__ keys in patterns

This patch subsumes CoverInitializedNameProduction to create an ObjectLiteralProduction which is now used to report the duplicate proto error as well.

This patch also changes ObjectLiteralChecker::CheckProperty
to record an ObjectLiteralProduction error instead of
bailing out immediately. Once we realize that we're in a
pattern, we rewind the error, otherwise we report the
error.

BUG=v8:5121

Review-Url: https://codereview.chromium.org/2255353002
Cr-Commit-Position: refs/heads/master@{#38764}
This commit is contained in:
gsathya 2016-08-19 18:01:39 -07:00 committed by Commit bot
parent 7da873b73f
commit fc52e32361
4 changed files with 41 additions and 35 deletions

View File

@ -22,12 +22,11 @@ namespace internal {
T(StrictModeFormalParametersProduction, 5) \ T(StrictModeFormalParametersProduction, 5) \
T(ArrowFormalParametersProduction, 6) \ T(ArrowFormalParametersProduction, 6) \
T(LetPatternProduction, 7) \ T(LetPatternProduction, 7) \
T(CoverInitializedNameProduction, 8) \ T(ObjectLiteralProduction, 8) \
T(TailCallExpressionProduction, 9) \ T(TailCallExpressionProduction, 9) \
T(AsyncArrowFormalParametersProduction, 10) \ T(AsyncArrowFormalParametersProduction, 10) \
T(AsyncBindingPatternProduction, 11) T(AsyncBindingPatternProduction, 11)
template <typename Traits> template <typename Traits>
class ExpressionClassifier { class ExpressionClassifier {
public: public:
@ -74,7 +73,7 @@ class ExpressionClassifier {
AllProductions = AllProductions =
(ExpressionProductions | PatternProductions | (ExpressionProductions | PatternProductions |
FormalParametersProductions | ArrowFormalParametersProduction | FormalParametersProductions | ArrowFormalParametersProduction |
CoverInitializedNameProduction | AsyncArrowFormalParametersProduction) ObjectLiteralProduction | AsyncArrowFormalParametersProduction)
}; };
enum FunctionProperties : unsigned { enum FunctionProperties : unsigned {
@ -187,12 +186,12 @@ class ExpressionClassifier {
return reported_error(kLetPatternProduction); return reported_error(kLetPatternProduction);
} }
V8_INLINE bool has_cover_initialized_name() const { V8_INLINE bool has_object_literal_error() const {
return !is_valid(CoverInitializedNameProduction); return !is_valid(ObjectLiteralProduction);
} }
V8_INLINE const Error& cover_initialized_name_error() const { V8_INLINE const Error& object_literal_error() const {
return reported_error(kCoverInitializedNameProduction); return reported_error(kObjectLiteralProduction);
} }
V8_INLINE bool has_tail_call_expression() const { V8_INLINE bool has_tail_call_expression() const {
@ -201,6 +200,7 @@ class ExpressionClassifier {
V8_INLINE const Error& tail_call_expression_error() const { V8_INLINE const Error& tail_call_expression_error() const {
return reported_error(kTailCallExpressionProduction); return reported_error(kTailCallExpressionProduction);
} }
V8_INLINE const Error& async_arrow_formal_parameters_error() const { V8_INLINE const Error& async_arrow_formal_parameters_error() const {
return reported_error(kAsyncArrowFormalParametersProduction); return reported_error(kAsyncArrowFormalParametersProduction);
} }
@ -314,12 +314,12 @@ class ExpressionClassifier {
Add(Error(loc, message, kLetPatternProduction, arg)); Add(Error(loc, message, kLetPatternProduction, arg));
} }
void RecordCoverInitializedNameError(const Scanner::Location& loc, void RecordObjectLiteralError(const Scanner::Location& loc,
MessageTemplate::Template message, MessageTemplate::Template message,
const char* arg = nullptr) { const char* arg = nullptr) {
if (has_cover_initialized_name()) return; if (has_object_literal_error()) return;
invalid_productions_ |= CoverInitializedNameProduction; invalid_productions_ |= ObjectLiteralProduction;
Add(Error(loc, message, kCoverInitializedNameProduction, arg)); Add(Error(loc, message, kObjectLiteralProduction, arg));
} }
void RecordTailCallExpressionError(const Scanner::Location& loc, void RecordTailCallExpressionError(const Scanner::Location& loc,
@ -330,11 +330,11 @@ class ExpressionClassifier {
Add(Error(loc, message, kTailCallExpressionProduction, arg)); Add(Error(loc, message, kTailCallExpressionProduction, arg));
} }
void ForgiveCoverInitializedNameError() { void ForgiveObjectLiteralError() {
if (!(invalid_productions_ & CoverInitializedNameProduction)) return; if (!(invalid_productions_ & ObjectLiteralProduction)) return;
Error& e = reported_error(kCoverInitializedNameProduction); Error& e = reported_error(kObjectLiteralProduction);
e.kind = kUnusedError; e.kind = kUnusedError;
invalid_productions_ &= ~CoverInitializedNameProduction; invalid_productions_ &= ~ObjectLiteralProduction;
} }
void ForgiveAssignmentPatternError() { void ForgiveAssignmentPatternError() {

View File

@ -910,12 +910,12 @@ class ParserBase : public Traits {
void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) { void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) {
if (!classifier->is_valid_expression() || if (!classifier->is_valid_expression() ||
classifier->has_cover_initialized_name()) { classifier->has_object_literal_error()) {
const Scanner::Location& a = classifier->expression_error().location; const Scanner::Location& a = classifier->expression_error().location;
const Scanner::Location& b = const Scanner::Location& b =
classifier->cover_initialized_name_error().location; classifier->object_literal_error().location;
if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) { if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
ReportClassifierError(classifier->cover_initialized_name_error()); ReportClassifierError(classifier->object_literal_error());
} else { } else {
ReportClassifierError(classifier->expression_error()); ReportClassifierError(classifier->expression_error());
} }
@ -1202,7 +1202,8 @@ class ParserBase : public Traits {
explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {} explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
virtual void CheckProperty(Token::Value property, PropertyKind type, virtual void CheckProperty(Token::Value property, PropertyKind type,
MethodKind method_type, bool* ok) = 0; MethodKind method_type,
ExpressionClassifier* classifier, bool* ok) = 0;
virtual ~ObjectLiteralCheckerBase() {} virtual ~ObjectLiteralCheckerBase() {}
@ -1221,7 +1222,8 @@ class ParserBase : public Traits {
: ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {} : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
void CheckProperty(Token::Value property, PropertyKind type, void CheckProperty(Token::Value property, PropertyKind type,
MethodKind method_type, bool* ok) override; MethodKind method_type, ExpressionClassifier* classifier,
bool* ok) override;
private: private:
bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); } bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
@ -1236,7 +1238,8 @@ class ParserBase : public Traits {
: ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {} : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
void CheckProperty(Token::Value property, PropertyKind type, void CheckProperty(Token::Value property, PropertyKind type,
MethodKind method_type, bool* ok) override; MethodKind method_type, ExpressionClassifier* classifier,
bool* ok) override;
private: private:
bool IsConstructor() { bool IsConstructor() {
@ -1980,6 +1983,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
// PropertyName ':' AssignmentExpression // PropertyName ':' AssignmentExpression
if (!*is_computed_name) { if (!*is_computed_name) {
checker->CheckProperty(name_token, kValueProperty, MethodKind::kNormal, checker->CheckProperty(name_token, kValueProperty, MethodKind::kNormal,
classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} }
Consume(Token::COLON); Consume(Token::COLON);
@ -2044,7 +2048,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
ExpressionClassifier::ExpressionProductions); ExpressionClassifier::ExpressionProductions);
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
kNoSourcePosition); kNoSourcePosition);
classifier->RecordCoverInitializedNameError( classifier->RecordObjectLiteralError(
Scanner::Location(next_beg_pos, scanner()->location().end_pos), Scanner::Location(next_beg_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidCoverInitializedName); MessageTemplate::kInvalidCoverInitializedName);
@ -2080,6 +2084,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
if (!*is_computed_name) { if (!*is_computed_name) {
checker->CheckProperty(name_token, kMethodProperty, method_kind, checker->CheckProperty(name_token, kMethodProperty, method_kind,
classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} }
@ -2130,6 +2135,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
if (!*is_computed_name) { if (!*is_computed_name) {
checker->CheckProperty(name_token, kAccessorProperty, method_kind, checker->CheckProperty(name_token, kAccessorProperty, method_kind,
classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} }
@ -2416,7 +2422,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
ExpressionClassifier::ExpressionProductions | ExpressionClassifier::ExpressionProductions |
ExpressionClassifier::PatternProductions | ExpressionClassifier::PatternProductions |
ExpressionClassifier::FormalParametersProductions | ExpressionClassifier::FormalParametersProductions |
ExpressionClassifier::CoverInitializedNameProduction | ExpressionClassifier::ObjectLiteralProduction |
ExpressionClassifier::AsyncArrowFormalParametersProduction, ExpressionClassifier::AsyncArrowFormalParametersProduction,
false); false);
@ -2433,7 +2439,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
CheckNoTailCallExpressions(classifier, CHECK_OK); CheckNoTailCallExpressions(classifier, CHECK_OK);
if (IsValidPattern(expression) && peek() == Token::ASSIGN) { if (IsValidPattern(expression) && peek() == Token::ASSIGN) {
classifier->ForgiveCoverInitializedNameError(); classifier->ForgiveObjectLiteralError();
ValidateAssignmentPattern(classifier, CHECK_OK); ValidateAssignmentPattern(classifier, CHECK_OK);
is_destructuring_assignment = true; is_destructuring_assignment = true;
} else { } else {
@ -2461,7 +2467,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
classifier->Accumulate( classifier->Accumulate(
&rhs_classifier, &rhs_classifier,
ExpressionClassifier::ExpressionProductions | ExpressionClassifier::ExpressionProductions |
ExpressionClassifier::CoverInitializedNameProduction | ExpressionClassifier::ObjectLiteralProduction |
ExpressionClassifier::AsyncArrowFormalParametersProduction); ExpressionClassifier::AsyncArrowFormalParametersProduction);
// TODO(1231235): We try to estimate the set of properties set by // TODO(1231235): We try to estimate the set of properties set by
@ -3702,7 +3708,7 @@ void ParserBase<Traits>::CheckDestructuringElement(
template <typename Traits> template <typename Traits>
void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
Token::Value property, PropertyKind type, MethodKind method_type, Token::Value property, PropertyKind type, MethodKind method_type,
bool* ok) { ExpressionClassifier* classifier, bool* ok) {
DCHECK(!IsStaticMethod(method_type)); DCHECK(!IsStaticMethod(method_type));
DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty); DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty);
@ -3710,19 +3716,18 @@ void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
if (type == kValueProperty && IsProto()) { if (type == kValueProperty && IsProto()) {
if (has_seen_proto_) { if (has_seen_proto_) {
this->parser()->ReportMessage(MessageTemplate::kDuplicateProto); classifier->RecordObjectLiteralError(
*ok = false; this->scanner()->location(), MessageTemplate::kDuplicateProto);
return; return;
} }
has_seen_proto_ = true; has_seen_proto_ = true;
return;
} }
} }
template <typename Traits> template <typename Traits>
void ParserBase<Traits>::ClassLiteralChecker::CheckProperty( void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
Token::Value property, PropertyKind type, MethodKind method_type, Token::Value property, PropertyKind type, MethodKind method_type,
bool* ok) { ExpressionClassifier* classifier, bool* ok) {
DCHECK(type == kMethodProperty || type == kAccessorProperty); DCHECK(type == kMethodProperty || type == kAccessorProperty);
if (property == Token::SMI || property == Token::NUMBER) return; if (property == Token::SMI || property == Token::NUMBER) return;

View File

@ -6342,6 +6342,7 @@ TEST(DestructuringPositiveTests) {
"[...rest]", "[...rest]",
"[a,b,...rest]", "[a,b,...rest]",
"[a,,...rest]", "[a,,...rest]",
"{ __proto__: x, __proto__: y}",
"{arguments: x}", "{arguments: x}",
"{eval: x}", "{eval: x}",
NULL}; NULL};
@ -6629,6 +6630,7 @@ TEST(DestructuringAssignmentPositiveTests) {
"{ x : [ foo()[y] = 10 ] = {} }", "{ x : [ foo()[y] = 10 ] = {} }",
"{ x : [ y.z = 10 ] = {} }", "{ x : [ y.z = 10 ] = {} }",
"{ x : [ y[z] = 10 ] = {} }", "{ x : [ y[z] = 10 ] = {} }",
"{ z : { __proto__: x, __proto__: y } = z }"
"[ x ]", "[ x ]",
"[ foo().x ]", "[ foo().x ]",
@ -6748,6 +6750,8 @@ TEST(DestructuringAssignmentPositiveTests) {
"var x; (true ? { x = true } = {} : { x = false } = {})", "var x; (true ? { x = true } = {} : { x = false } = {})",
"var q, x; (q, { x = 10 } = {});", "var q, x; (q, { x = 10 } = {});",
"var { x = 10 } = { x = 20 } = {};", "var { x = 10 } = { x = 20 } = {};",
"var { __proto__: x, __proto__: y } = {}",
"({ __proto__: x, __proto__: y } = {})",
"var { x = 10 } = (o = { x = 20 } = {});", "var { x = 10 } = (o = { x = 20 } = {});",
"var x; (({ x = 10 } = { x = 20 } = {}) => x)({})", "var x; (({ x = 10 } = { x = 20 } = {}) => x)({})",
NULL, NULL,

View File

@ -359,9 +359,6 @@
'annexB/built-ins/Object/prototype/__lookupGetter__/this-non-obj': [FAIL], 'annexB/built-ins/Object/prototype/__lookupGetter__/this-non-obj': [FAIL],
'annexB/built-ins/Object/prototype/__lookupSetter__/this-non-obj': [FAIL], 'annexB/built-ins/Object/prototype/__lookupSetter__/this-non-obj': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=5121
'language/expressions/assignment/destructuring/obj-prop-__proto__dup': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4973 # https://bugs.chromium.org/p/v8/issues/detail?id=4973
'language/literals/numeric/non-octal-decimal-integer-strict': [FAIL], 'language/literals/numeric/non-octal-decimal-integer-strict': [FAIL],