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