[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:
parent
7da873b73f
commit
fc52e32361
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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],
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user