Commit ef52836c authored by adamk's avatar adamk Committed by Commit bot

[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}
parent 316b1e75
......@@ -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(&parameters.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(&parameters, 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))) {
......
// 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 }
*%(basename)s:7: ReferenceError: Invalid left-hand side in assignment
function f() { new.target = 5 }
^^^^^^^^^^
ReferenceError: Invalid left-hand side in assignment
// 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 {}); }
*%(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
// 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++ }
*%(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
// 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 }
*%(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);
})();
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