Commit fc52e323 authored by gsathya's avatar gsathya Committed by Commit bot

[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}
parent 7da873b7
......@@ -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,
void RecordObjectLiteralError(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));
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],
......
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