[es6] Make assignment to new.target an early ReferenceError
In doing so, fix calls CheckAndRewriteReferenceExpression to take proper start and end positions (instead of just pointing at the first token in the LHS expression). BUG=v8:4370 LOG=n Review URL: https://codereview.chromium.org/1290013002 Cr-Commit-Position: refs/heads/master@{#30166}
This commit is contained in:
parent
316b1e758b
commit
ef52836cd8
10
src/ast.h
10
src/ast.h
@ -1639,7 +1639,9 @@ class VariableProxy final : public Expression {
|
||||
public:
|
||||
DECLARE_NODE_TYPE(VariableProxy)
|
||||
|
||||
bool IsValidReferenceExpression() const override { return !is_this(); }
|
||||
bool IsValidReferenceExpression() const override {
|
||||
return !is_this() && !is_new_target();
|
||||
}
|
||||
|
||||
bool IsArguments() const { return is_resolved() && var()->is_arguments(); }
|
||||
|
||||
@ -1670,6 +1672,11 @@ class VariableProxy final : public Expression {
|
||||
bit_field_ = IsResolvedField::update(bit_field_, true);
|
||||
}
|
||||
|
||||
bool is_new_target() const { return IsNewTargetField::decode(bit_field_); }
|
||||
void set_is_new_target() {
|
||||
bit_field_ = IsNewTargetField::update(bit_field_, true);
|
||||
}
|
||||
|
||||
int end_position() const { return end_position_; }
|
||||
|
||||
// Bind this proxy to the variable var.
|
||||
@ -1705,6 +1712,7 @@ class VariableProxy final : public Expression {
|
||||
class IsThisField : public BitField8<bool, 0, 1> {};
|
||||
class IsAssignedField : public BitField8<bool, 1, 1> {};
|
||||
class IsResolvedField : public BitField8<bool, 2, 1> {};
|
||||
class IsNewTargetField : public BitField8<bool, 3, 1> {};
|
||||
|
||||
// Start with 16-bit (or smaller) field, which should get packed together
|
||||
// with Expression's trailing 16-bit field.
|
||||
|
@ -789,9 +789,11 @@ Expression* ParserTraits::NewTargetExpression(Scope* scope,
|
||||
AstNodeFactory* factory,
|
||||
int pos) {
|
||||
static const int kNewTargetStringLength = 10;
|
||||
return scope->NewUnresolved(
|
||||
auto proxy = scope->NewUnresolved(
|
||||
factory, parser_->ast_value_factory()->new_target_string(),
|
||||
Variable::NORMAL, pos, pos + kNewTargetStringLength);
|
||||
proxy->set_is_new_target();
|
||||
return proxy;
|
||||
}
|
||||
|
||||
|
||||
@ -3679,8 +3681,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
CHECK_OK);
|
||||
}
|
||||
} else {
|
||||
Scanner::Location lhs_location = scanner()->peek_location();
|
||||
int lhs_beg_pos = peek_position();
|
||||
Expression* expression = ParseExpression(false, CHECK_OK);
|
||||
int lhs_end_pos = scanner()->location().end_pos;
|
||||
ForEachStatement::VisitMode mode;
|
||||
bool accept_OF = expression->IsVariableProxy();
|
||||
is_let_identifier_expression =
|
||||
@ -3691,8 +3694,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
if (CheckInOrOf(accept_OF, &mode, ok)) {
|
||||
if (!*ok) return nullptr;
|
||||
expression = this->CheckAndRewriteReferenceExpression(
|
||||
expression, lhs_location, MessageTemplate::kInvalidLhsInFor,
|
||||
CHECK_OK);
|
||||
expression, lhs_beg_pos, lhs_end_pos,
|
||||
MessageTemplate::kInvalidLhsInFor, CHECK_OK);
|
||||
|
||||
ForEachStatement* loop =
|
||||
factory()->NewForEachStatement(mode, labels, stmt_pos);
|
||||
@ -3711,8 +3714,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
return loop;
|
||||
|
||||
} else {
|
||||
init =
|
||||
factory()->NewExpressionStatement(expression, lhs_location.beg_pos);
|
||||
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -918,6 +918,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
||||
lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
|
||||
if (CheckInOrOf(lhs.IsIdentifier(), &mode, ok)) {
|
||||
if (!*ok) return Statement::Default();
|
||||
// TODO(adamk): Should call CheckAndRewriteReferenceExpression here
|
||||
// to catch early errors if lhs is not a valid reference expression.
|
||||
ParseExpression(true, CHECK_OK);
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
ParseSubStatement(CHECK_OK);
|
||||
|
@ -713,7 +713,7 @@ class ParserBase : public Traits {
|
||||
// left-hand side of assignments). Although ruled out by ECMA as early errors,
|
||||
// we allow calls for web compatibility and rewrite them to a runtime throw.
|
||||
ExpressionT CheckAndRewriteReferenceExpression(
|
||||
ExpressionT expression, Scanner::Location location,
|
||||
ExpressionT expression, int beg_pos, int end_pos,
|
||||
MessageTemplate::Template message, bool* ok);
|
||||
|
||||
// Used to validate property names in object literals and class literals
|
||||
@ -2821,7 +2821,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
// YieldExpression
|
||||
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
||||
|
||||
Scanner::Location lhs_location = scanner()->peek_location();
|
||||
int lhs_beg_pos = peek_position();
|
||||
|
||||
if (peek() == Token::YIELD && is_generator()) {
|
||||
return this->ParseYieldExpression(classifier, ok);
|
||||
@ -2841,13 +2841,13 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
|
||||
parenthesized_formals, CHECK_OK);
|
||||
Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos);
|
||||
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
|
||||
Scope* scope =
|
||||
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
|
||||
FormalParametersT parameters(scope);
|
||||
checkpoint.Restore(¶meters.materialized_literals_count);
|
||||
|
||||
scope->set_start_position(lhs_location.beg_pos);
|
||||
scope->set_start_position(lhs_beg_pos);
|
||||
Scanner::Location duplicate_loc = Scanner::Location::invalid();
|
||||
this->ParseArrowFunctionFormalParameterList(¶meters, expression, loc,
|
||||
&duplicate_loc, CHECK_OK);
|
||||
@ -2877,8 +2877,8 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
}
|
||||
|
||||
expression = this->CheckAndRewriteReferenceExpression(
|
||||
expression, lhs_location, MessageTemplate::kInvalidLhsInAssignment,
|
||||
CHECK_OK);
|
||||
expression, lhs_beg_pos, scanner()->location().end_pos,
|
||||
MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
|
||||
expression = this->MarkExpressionAsAssigned(expression);
|
||||
|
||||
Token::Value op = Next(); // Get assignment operator.
|
||||
@ -3094,11 +3094,11 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
||||
} else if (Token::IsCountOp(op)) {
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
op = Next();
|
||||
Scanner::Location lhs_location = scanner()->peek_location();
|
||||
int beg_pos = peek_position();
|
||||
ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
|
||||
expression = this->CheckAndRewriteReferenceExpression(
|
||||
expression, lhs_location, MessageTemplate::kInvalidLhsInPrefixOp,
|
||||
CHECK_OK);
|
||||
expression, beg_pos, scanner()->location().end_pos,
|
||||
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
|
||||
this->MarkExpressionAsAssigned(expression);
|
||||
|
||||
return factory()->NewCountOperation(op,
|
||||
@ -3119,7 +3119,7 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
|
||||
// PostfixExpression ::
|
||||
// LeftHandSideExpression ('++' | '--')?
|
||||
|
||||
Scanner::Location lhs_location = scanner()->peek_location();
|
||||
int lhs_beg_pos = peek_position();
|
||||
ExpressionT expression =
|
||||
this->ParseLeftHandSideExpression(classifier, CHECK_OK);
|
||||
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
||||
@ -3127,8 +3127,8 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
|
||||
expression = this->CheckAndRewriteReferenceExpression(
|
||||
expression, lhs_location, MessageTemplate::kInvalidLhsInPostfixOp,
|
||||
CHECK_OK);
|
||||
expression, lhs_beg_pos, scanner()->location().end_pos,
|
||||
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
|
||||
expression = this->MarkExpressionAsAssigned(expression);
|
||||
|
||||
Token::Value next = Next();
|
||||
@ -3936,8 +3936,9 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start,
|
||||
template <typename Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::CheckAndRewriteReferenceExpression(
|
||||
ExpressionT expression, Scanner::Location location,
|
||||
ExpressionT expression, int beg_pos, int end_pos,
|
||||
MessageTemplate::Template message, bool* ok) {
|
||||
Scanner::Location location(beg_pos, end_pos);
|
||||
if (this->IsIdentifier(expression)) {
|
||||
if (is_strict(language_mode()) &&
|
||||
this->IsEvalOrArguments(this->AsIdentifier(expression))) {
|
||||
|
7
test/message/new-target-assignment.js
Normal file
7
test/message/new-target-assignment.js
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-new-target
|
||||
|
||||
function f() { new.target = 5 }
|
4
test/message/new-target-assignment.out
Normal file
4
test/message/new-target-assignment.out
Normal file
@ -0,0 +1,4 @@
|
||||
*%(basename)s:7: ReferenceError: Invalid left-hand side in assignment
|
||||
function f() { new.target = 5 }
|
||||
^^^^^^^^^^
|
||||
ReferenceError: Invalid left-hand side in assignment
|
7
test/message/new-target-for-loop.js
Normal file
7
test/message/new-target-for-loop.js
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-new-target
|
||||
|
||||
function f() { for (new.target in {}); }
|
4
test/message/new-target-for-loop.out
Normal file
4
test/message/new-target-for-loop.out
Normal file
@ -0,0 +1,4 @@
|
||||
*%(basename)s:7: ReferenceError: Invalid left-hand side in for-loop
|
||||
function f() { for (new.target in {}); }
|
||||
^^^^^^^^^^
|
||||
ReferenceError: Invalid left-hand side in for-loop
|
7
test/message/new-target-postfix-op.js
Normal file
7
test/message/new-target-postfix-op.js
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-new-target
|
||||
|
||||
function f() { new.target++ }
|
4
test/message/new-target-postfix-op.out
Normal file
4
test/message/new-target-postfix-op.out
Normal file
@ -0,0 +1,4 @@
|
||||
*%(basename)s:7: ReferenceError: Invalid left-hand side expression in postfix operation
|
||||
function f() { new.target++ }
|
||||
^^^^^^^^^^
|
||||
ReferenceError: Invalid left-hand side expression in postfix operation
|
7
test/message/new-target-prefix-op.js
Normal file
7
test/message/new-target-prefix-op.js
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-new-target
|
||||
|
||||
function f() { ++new.target }
|
4
test/message/new-target-prefix-op.out
Normal file
4
test/message/new-target-prefix-op.out
Normal file
@ -0,0 +1,4 @@
|
||||
*%(basename)s:7: ReferenceError: Invalid left-hand side expression in prefix operation
|
||||
function f() { ++new.target }
|
||||
^^^^^^^^^^
|
||||
ReferenceError: Invalid left-hand side expression in prefix operation
|
@ -384,3 +384,15 @@
|
||||
function f6() { with ({'new.target': 42}) return new.target }
|
||||
assertSame(f6, new f6);
|
||||
})();
|
||||
|
||||
|
||||
(function TestEarlyErrors() {
|
||||
assertThrows(function() { Function("new.target = 42"); }, ReferenceError);
|
||||
assertThrows(function() { Function("var foo = 1; new.target = foo = 42"); }, ReferenceError);
|
||||
assertThrows(function() { Function("var foo = 1; foo = new.target = 42"); }, ReferenceError);
|
||||
assertThrows(function() { Function("new.target--"); }, ReferenceError);
|
||||
assertThrows(function() { Function("--new.target"); }, ReferenceError);
|
||||
assertThrows(function() { Function("(new.target)++"); }, ReferenceError);
|
||||
assertThrows(function() { Function("++(new.target)"); }, ReferenceError);
|
||||
assertThrows(function() { Function("for (new.target of {});"); }, ReferenceError);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user