Reviewers: rossberg,
Description:
[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
Please review this at https://codereview.chromium.org/1290013002/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+63, -33 lines):
M src/ast.h
M src/parser.cc
M src/preparser.h
A + test/message/new-target-assignment.js
A test/message/new-target-assignment.out
A + test/message/new-target-for-loop.js
A test/message/new-target-for-loop.out
A + test/message/new-target-postfix-op.js
A test/message/new-target-postfix-op.out
A + test/message/new-target-prefix-op.js
A test/message/new-target-prefix-op.out
M test/mjsunit/harmony/new-target.js
Index: src/ast.h
diff --git a/src/ast.h b/src/ast.h
index
f7f713afa6cab5e1bc16a2fc917145b7449d6193..e5e32617deadc5bc2bd13b396a425d4a5fa7dc64
100644
--- a/src/ast.h
+++ b/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.
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index
e53352d26c1d459dd732567c55b18373897ac7ee..5b5e613436687bfd515974b911a857fa6e05dca8
100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -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);
}
}
}
Index: src/preparser.h
diff --git a/src/preparser.h b/src/preparser.h
index
61cb883f8a664f8695ce78de9477b6bae6995f89..65951f3cdb19f7f2c86e5a6cffed1bcf3f4872c0
100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -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))) {
Index: test/message/new-target-assignment.js
diff --git a/test/message/arrow-strict-eval-bare-parameter.js
b/test/message/new-target-assignment.js
similarity index 73%
copy from test/message/arrow-strict-eval-bare-parameter.js
copy to test/message/new-target-assignment.js
index
d5692517dd3e59b3d359d70ab455ad1c2b0f0bad..f257d1a5b573c93c219dcac805afd7efb22556e2
100644
--- a/test/message/arrow-strict-eval-bare-parameter.js
+++ b/test/message/new-target-assignment.js
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Flags: --harmony-arrow-functions
+// Flags: --harmony-new-target
-"use strict";
-eval => 42
+function f() { new.target = 5 }
Index: test/message/new-target-assignment.out
diff --git a/test/message/new-target-assignment.out
b/test/message/new-target-assignment.out
new file mode 100644
index
0000000000000000000000000000000000000000..5431bd0fc0f64d39508fa50e9d85af9e680701a2
--- /dev/null
+++ b/test/message/new-target-assignment.out
@@ -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
Index: test/message/new-target-for-loop.js
diff --git a/test/message/export-duplicate.js
b/test/message/new-target-for-loop.js
similarity index 70%
copy from test/message/export-duplicate.js
copy to test/message/new-target-for-loop.js
index
f45aefe13f8a427bd7ad5bced7da24db32ec5e25..76a8eecba22967a400ae35773f763fe596300f2c
100644
--- a/test/message/export-duplicate.js
+++ b/test/message/new-target-for-loop.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// MODULE
+// Flags: --harmony-new-target
-var a, b;
-export { a };
-export { a, b };
+function f() { for (new.target in {}); }
Index: test/message/new-target-for-loop.out
diff --git a/test/message/new-target-for-loop.out
b/test/message/new-target-for-loop.out
new file mode 100644
index
0000000000000000000000000000000000000000..30f1f75d7e33b048904cf242b32f14e510a1ed1a
--- /dev/null
+++ b/test/message/new-target-for-loop.out
@@ -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
Index: test/message/new-target-postfix-op.js
diff --git a/test/message/arrow-strict-eval-bare-parameter.js
b/test/message/new-target-postfix-op.js
similarity index 73%
copy from test/message/arrow-strict-eval-bare-parameter.js
copy to test/message/new-target-postfix-op.js
index
d5692517dd3e59b3d359d70ab455ad1c2b0f0bad..573f3ae3a7176fc74034d4c41b16a84771f2ebb9
100644
--- a/test/message/arrow-strict-eval-bare-parameter.js
+++ b/test/message/new-target-postfix-op.js
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Flags: --harmony-arrow-functions
+// Flags: --harmony-new-target
-"use strict";
-eval => 42
+function f() { new.target++ }
Index: test/message/new-target-postfix-op.out
diff --git a/test/message/new-target-postfix-op.out
b/test/message/new-target-postfix-op.out
new file mode 100644
index
0000000000000000000000000000000000000000..17f2081ed63d5f11dd0d1ae8d587e6319fe9235d
--- /dev/null
+++ b/test/message/new-target-postfix-op.out
@@ -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
Index: test/message/new-target-prefix-op.js
diff --git a/test/message/arrow-strict-eval-bare-parameter.js
b/test/message/new-target-prefix-op.js
similarity index 73%
copy from test/message/arrow-strict-eval-bare-parameter.js
copy to test/message/new-target-prefix-op.js
index
d5692517dd3e59b3d359d70ab455ad1c2b0f0bad..ad2f98a46c773a7a4a66f58b5a9f63f428af7416
100644
--- a/test/message/arrow-strict-eval-bare-parameter.js
+++ b/test/message/new-target-prefix-op.js
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Flags: --harmony-arrow-functions
+// Flags: --harmony-new-target
-"use strict";
-eval => 42
+function f() { ++new.target }
Index: test/message/new-target-prefix-op.out
diff --git a/test/message/new-target-prefix-op.out
b/test/message/new-target-prefix-op.out
new file mode 100644
index
0000000000000000000000000000000000000000..19c847f23eec745412a539d4dada1c43d3f9522e
--- /dev/null
+++ b/test/message/new-target-prefix-op.out
@@ -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
Index: test/mjsunit/harmony/new-target.js
diff --git a/test/mjsunit/harmony/new-target.js
b/test/mjsunit/harmony/new-target.js
index
fa5b37282018d2615a83dc05cfff0f4738aefa38..394e93901299129ce20c334e282c3f1eab4e9218
100644
--- a/test/mjsunit/harmony/new-target.js
+++ b/test/mjsunit/harmony/new-target.js
@@ -384,3 +384,11 @@
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("new.target--"); }, ReferenceError);
+ assertThrows(function() { Function("--new.target"); }, ReferenceError);
+ assertThrows(function() { Function("for (new.target of {});"); },
ReferenceError);
+})();
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.