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

View File

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

View File

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

View File

@ -359,9 +359,6 @@
'annexB/built-ins/Object/prototype/__lookupGetter__/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
'language/literals/numeric/non-octal-decimal-integer-strict': [FAIL],