[parser] Create arrow function scopes while parsing the head
This simplifies NextArrowFunctionInfo, allows us to Scope::Snapshot::Reparent directly rather than moving it, and allows us to skip reparenting in the simple parameter arrow function cases. This is a reland of https://chromium-review.googlesource.com/c/v8/v8/+/1397664, simply splitting out the arrow-function-name-inferring part. Change-Id: I640d911a9607edc3bbb0e5ff3bf992094e4159e4 Reviewed-on: https://chromium-review.googlesource.com/c/1397701 Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#58570}
This commit is contained in:
parent
b962c07107
commit
76f8893699
@ -888,11 +888,15 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
|
||||
outer_closure->locals_.Rewind(top_local_);
|
||||
|
||||
// Move eval calls since Snapshot's creation into new_parent.
|
||||
if (outer_scope_and_calls_eval_.GetPayload()) {
|
||||
if (outer_scope_and_calls_eval_->scope_calls_eval_) {
|
||||
new_parent->scope_calls_eval_ = true;
|
||||
new_parent->inner_scope_calls_eval_ = true;
|
||||
}
|
||||
|
||||
// We are in the arrow function case. The calls eval we may have recorded
|
||||
// is intended for the inner scope and we should simply restore the
|
||||
// original "calls eval" flag of the outer scope.
|
||||
RestoreEvalFlag();
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
@ -147,24 +147,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
outer_scope_and_calls_eval_.GetPayload();
|
||||
}
|
||||
|
||||
Snapshot& operator=(Snapshot&& source) V8_NOEXCEPT {
|
||||
outer_scope_and_calls_eval_.SetPointer(
|
||||
source.outer_scope_and_calls_eval_.GetPointer());
|
||||
outer_scope_and_calls_eval_.SetPayload(
|
||||
outer_scope_and_calls_eval_->scope_calls_eval_);
|
||||
top_inner_scope_ = source.top_inner_scope_;
|
||||
top_unresolved_ = source.top_unresolved_;
|
||||
top_local_ = source.top_local_;
|
||||
|
||||
// We are in the arrow function case. The calls eval we may have recorded
|
||||
// is intended for the inner scope and we should simply restore the
|
||||
// original "calls eval" flag of the outer scope.
|
||||
source.RestoreEvalFlag();
|
||||
source.Clear();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Reparent(DeclarationScope* new_parent);
|
||||
bool IsCleared() const {
|
||||
return outer_scope_and_calls_eval_.GetPointer() == nullptr;
|
||||
|
@ -271,8 +271,6 @@ class ParserBase {
|
||||
pointer_buffer_.reserve(128);
|
||||
}
|
||||
|
||||
~ParserBase() { next_arrow_function_info_.scope_snapshot.Clear(); }
|
||||
|
||||
#define ALLOW_ACCESSORS(name) \
|
||||
bool allow_##name() const { return allow_##name##_; } \
|
||||
void set_allow_##name(bool allow) { allow_##name##_ = allow; }
|
||||
@ -1369,7 +1367,6 @@ class ParserBase {
|
||||
// Preallocating the struct as part of the parser minimizes the cost of
|
||||
// supporting arrow functions on non-arrow expressions.
|
||||
struct NextArrowFunctionInfo {
|
||||
Scope::Snapshot scope_snapshot;
|
||||
// `rewritable_length`: length of the destructuring_assignments_to_rewrite()
|
||||
// queue in the parent function state, prior to parsing of formal
|
||||
// parameters. If the arrow function is lazy, any items added during formal
|
||||
@ -1378,19 +1375,15 @@ class ParserBase {
|
||||
Scanner::Location strict_parameter_error_location =
|
||||
Scanner::Location::invalid();
|
||||
MessageTemplate strict_parameter_error_message = MessageTemplate::kNone;
|
||||
FunctionKind kind = FunctionKind::kArrowFunction;
|
||||
bool has_simple_parameter_list = true;
|
||||
DeclarationScope* scope = nullptr;
|
||||
|
||||
bool HasInitialState() const {
|
||||
return rewritable_length == -1 && scope_snapshot.IsCleared() &&
|
||||
kind == FunctionKind::kArrowFunction && has_simple_parameter_list;
|
||||
return rewritable_length == -1 && scope == nullptr;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
rewritable_length = -1;
|
||||
scope_snapshot.Clear();
|
||||
kind = FunctionKind::kArrowFunction;
|
||||
has_simple_parameter_list = true;
|
||||
scope = nullptr;
|
||||
ClearStrictParameterError();
|
||||
DCHECK(HasInitialState());
|
||||
}
|
||||
@ -1646,8 +1639,7 @@ ParserBase<Impl>::ParsePrimaryExpression() {
|
||||
if (Token::IsAnyIdentifier(token)) {
|
||||
Consume(token);
|
||||
|
||||
IdentifierT name;
|
||||
InferName infer = InferName::kYes;
|
||||
FunctionKind kind = FunctionKind::kArrowFunction;
|
||||
|
||||
if (V8_UNLIKELY(token == Token::ASYNC &&
|
||||
!scanner()->HasLineTerminatorBeforeNext())) {
|
||||
@ -1658,28 +1650,30 @@ ParserBase<Impl>::ParsePrimaryExpression() {
|
||||
if (peek_any_identifier() && PeekAhead() == Token::ARROW) {
|
||||
token = Next();
|
||||
beg_pos = position();
|
||||
next_arrow_function_info_.kind = FunctionKind::kAsyncArrowFunction;
|
||||
infer = InferName::kNo;
|
||||
kind = FunctionKind::kAsyncArrowFunction;
|
||||
}
|
||||
}
|
||||
|
||||
if (V8_UNLIKELY(peek() == Token::ARROW)) {
|
||||
next_arrow_function_info_.scope = NewFunctionScope(kind);
|
||||
ArrowHeadParsingScope parsing_scope(
|
||||
impl(), next_arrow_function_info_.kind == FunctionKind::kArrowFunction
|
||||
impl(), kind == FunctionKind::kArrowFunction
|
||||
? ExpressionScope::kMaybeArrowParameterDeclaration
|
||||
: ExpressionScope::kMaybeAsyncArrowParameterDeclaration);
|
||||
next_arrow_function_info_.scope_snapshot =
|
||||
std::move(Scope::Snapshot(scope()));
|
||||
next_arrow_function_info_.rewritable_length = static_cast<int>(
|
||||
function_state_->destructuring_assignments_to_rewrite().size());
|
||||
name = ParseAndClassifyIdentifier(token);
|
||||
IdentifierT name = ParseAndClassifyIdentifier(token);
|
||||
ClassifyParameter(name, beg_pos, end_position());
|
||||
parsing_scope.ValidateDeclaration();
|
||||
} else {
|
||||
name = ParseAndClassifyIdentifier(token);
|
||||
FunctionState function_state(&function_state_, &scope_,
|
||||
next_arrow_function_info_.scope);
|
||||
InferName infer = kind == FunctionKind::kArrowFunction ? InferName::kYes
|
||||
: InferName::kNo;
|
||||
return impl()->ExpressionFromIdentifier(name, beg_pos, infer);
|
||||
}
|
||||
|
||||
return impl()->ExpressionFromIdentifier(name, beg_pos, infer);
|
||||
IdentifierT name = ParseAndClassifyIdentifier(token);
|
||||
return impl()->ExpressionFromIdentifier(name, beg_pos);
|
||||
}
|
||||
|
||||
if (Token::IsLiteral(token)) {
|
||||
@ -1704,17 +1698,18 @@ ParserBase<Impl>::ParsePrimaryExpression() {
|
||||
|
||||
case Token::LPAREN: {
|
||||
Consume(Token::LPAREN);
|
||||
Scope::Snapshot scope_snapshot(scope());
|
||||
int rewritable_length = static_cast<int>(
|
||||
function_state_->destructuring_assignments_to_rewrite().size());
|
||||
if (Check(Token::RPAREN)) {
|
||||
// ()=>x. The continuation that consumes the => is in
|
||||
// ParseAssignmentExpressionCoverGrammar.
|
||||
if (peek() != Token::ARROW) ReportUnexpectedToken(Token::RPAREN);
|
||||
next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot);
|
||||
next_arrow_function_info_.scope =
|
||||
NewFunctionScope(FunctionKind::kArrowFunction);
|
||||
next_arrow_function_info_.rewritable_length = rewritable_length;
|
||||
return factory()->NewEmptyParentheses(beg_pos);
|
||||
}
|
||||
Scope::Snapshot scope_snapshot(scope());
|
||||
ArrowHeadParsingScope maybe_arrow(
|
||||
impl(), ExpressionScope::kMaybeArrowParameterDeclaration);
|
||||
// Heuristically try to detect immediately called functions before
|
||||
@ -1729,9 +1724,12 @@ ParserBase<Impl>::ParsePrimaryExpression() {
|
||||
Expect(Token::RPAREN);
|
||||
|
||||
if (peek() == Token::ARROW) {
|
||||
next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot);
|
||||
next_arrow_function_info_.has_simple_parameter_list =
|
||||
maybe_arrow.has_simple_parameter_list();
|
||||
next_arrow_function_info_.scope =
|
||||
NewFunctionScope(FunctionKind::kArrowFunction);
|
||||
scope_snapshot.Reparent(next_arrow_function_info_.scope);
|
||||
if (!maybe_arrow.has_simple_parameter_list()) {
|
||||
next_arrow_function_info_.scope->SetHasNonSimpleParameters();
|
||||
}
|
||||
next_arrow_function_info_.rewritable_length = rewritable_length;
|
||||
maybe_arrow.ValidateDeclaration();
|
||||
} else {
|
||||
@ -2602,7 +2600,6 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() {
|
||||
// Arrow functions.
|
||||
if (V8_UNLIKELY(op == Token::ARROW)) {
|
||||
Scanner::Location loc(lhs_beg_pos, end_position());
|
||||
DeclarationScope* scope = NewFunctionScope(next_arrow_function_info_.kind);
|
||||
|
||||
if (!impl()->IsIdentifier(expression) && !expression->is_parenthesized()) {
|
||||
impl()->ReportMessageAt(
|
||||
@ -2611,20 +2608,15 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() {
|
||||
return impl()->FailureExpression();
|
||||
}
|
||||
|
||||
// Because the arrow's parameters were parsed in the outer scope,
|
||||
// we need to fix up the scope chain appropriately.
|
||||
next_arrow_function_info_.scope_snapshot.Reparent(scope);
|
||||
DeclarationScope* scope = next_arrow_function_info_.scope;
|
||||
scope->set_start_position(lhs_beg_pos);
|
||||
|
||||
FormalParametersT parameters(scope);
|
||||
parameters.set_strict_parameter_error(
|
||||
next_arrow_function_info_.strict_parameter_error_location,
|
||||
next_arrow_function_info_.strict_parameter_error_message);
|
||||
if (!next_arrow_function_info_.has_simple_parameter_list) {
|
||||
scope->SetHasNonSimpleParameters();
|
||||
parameters.is_simple = false;
|
||||
}
|
||||
parameters.is_simple = scope->has_simple_parameters();
|
||||
|
||||
scope->set_start_position(lhs_beg_pos);
|
||||
impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc);
|
||||
|
||||
expression = ParseArrowFunctionLiteral(parameters);
|
||||
@ -2907,12 +2899,13 @@ ParserBase<Impl>::ParseUnaryOrPrefixExpression() {
|
||||
|
||||
DCHECK(Token::IsCountOp(op));
|
||||
|
||||
if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) {
|
||||
if (V8_LIKELY(IsValidReferenceExpression(expression))) {
|
||||
if (peek() != Token::ARROW) impl()->MarkExpressionAsAssigned(expression);
|
||||
} else {
|
||||
expression = RewriteInvalidReferenceExpression(
|
||||
expression, expression_position, end_position(),
|
||||
MessageTemplate::kInvalidLhsInPrefixOp);
|
||||
}
|
||||
impl()->MarkExpressionAsAssigned(expression);
|
||||
|
||||
return factory()->NewCountOperation(op, true /* prefix */, expression,
|
||||
position());
|
||||
@ -3021,15 +3014,17 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
|
||||
if (V8_LIKELY(peek() == Token::ARROW)) {
|
||||
maybe_arrow.ValidateDeclaration();
|
||||
fni_.RemoveAsyncKeywordFromEnd();
|
||||
next_arrow_function_info_.kind = FunctionKind::kAsyncArrowFunction;
|
||||
next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot);
|
||||
next_arrow_function_info_.scope =
|
||||
NewFunctionScope(FunctionKind::kAsyncArrowFunction);
|
||||
scope_snapshot.Reparent(next_arrow_function_info_.scope);
|
||||
next_arrow_function_info_.rewritable_length = rewritable_length;
|
||||
// async () => ...
|
||||
if (!args.length()) return factory()->NewEmptyParentheses(pos);
|
||||
// async ( Arguments ) => ...
|
||||
ExpressionT result = impl()->ExpressionListToExpression(args);
|
||||
next_arrow_function_info_.has_simple_parameter_list =
|
||||
maybe_arrow.has_simple_parameter_list();
|
||||
if (!maybe_arrow.has_simple_parameter_list()) {
|
||||
next_arrow_function_info_.scope->SetHasNonSimpleParameters();
|
||||
}
|
||||
result->mark_parenthesized();
|
||||
return result;
|
||||
}
|
||||
@ -4061,10 +4056,13 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
|
||||
// In case we did not sucessfully preparse the function because of an
|
||||
// unidentified error we do a full reparse to return the error.
|
||||
ExpressionT expression = ParseConditionalExpression();
|
||||
Scanner::Location loc(scope()->start_position(), end_position());
|
||||
FormalParametersT parameters(formal_parameters.scope);
|
||||
parameters.is_simple =
|
||||
next_arrow_function_info_.has_simple_parameter_list;
|
||||
DeclarationScope* function_scope = next_arrow_function_info_.scope;
|
||||
FunctionState function_state(&function_state_, &scope_,
|
||||
function_scope);
|
||||
Scanner::Location loc(function_scope->start_position(),
|
||||
end_position());
|
||||
FormalParametersT parameters(function_scope);
|
||||
parameters.is_simple = function_scope->has_simple_parameters();
|
||||
impl()->DeclareArrowFunctionFormalParameters(¶meters, expression,
|
||||
loc);
|
||||
next_arrow_function_info_.Reset();
|
||||
|
Loading…
Reference in New Issue
Block a user