Commit a5f559c3 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[parser] Change how catch is parsed

- Directly declares the special catch variable from the parser-base.
- Tracks Scope on PreParserBlock and finds conflicting lexical declarations by
  simply walking the VariableMap of the block inserted for the pattern; or the
  catch variable in case of identifier.
- This also enables throwing errors for duplicate let in the preparser. We may
  have to back that out if it breaks something.

Bug: v8:2728, v8:7828
Change-Id: Id2eea62062533eb99cd6670c42a4b1da87139008
Reviewed-on: https://chromium-review.googlesource.com/c/1382095Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58353}
parent 42afba51
...@@ -1156,13 +1156,12 @@ Variable* Scope::DeclareVariableName(const AstRawString* name, ...@@ -1156,13 +1156,12 @@ Variable* Scope::DeclareVariableName(const AstRawString* name,
return var; return var;
} }
void Scope::DeclareCatchVariableName(const AstRawString* name) { Variable* Scope::DeclareCatchVariableName(const AstRawString* name) {
DCHECK(!already_resolved_); DCHECK(!already_resolved_);
DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
DCHECK(is_catch_scope()); DCHECK(is_catch_scope());
DCHECK(scope_info_.is_null()); DCHECK(scope_info_.is_null());
Declare(zone(), name, VariableMode::kVar); return Declare(zone(), name, VariableMode::kVar);
} }
void Scope::AddUnresolved(VariableProxy* proxy) { void Scope::AddUnresolved(VariableProxy* proxy) {
...@@ -1238,24 +1237,29 @@ Declaration* Scope::CheckConflictingVarDeclarations() { ...@@ -1238,24 +1237,29 @@ Declaration* Scope::CheckConflictingVarDeclarations() {
return nullptr; return nullptr;
} }
Declaration* Scope::CheckLexDeclarationsConflictingWith( const AstRawString* Scope::FindLexVariableDeclaredIn(Scope* scope) {
const ZonePtrList<const AstRawString>& names) {
DCHECK(is_block_scope()); DCHECK(is_block_scope());
for (int i = 0; i < names.length(); ++i) { const VariableMap& variables = scope->variables_;
Variable* var = LookupLocal(names.at(i)); for (ZoneHashMap::Entry* p = variables.Start(); p != nullptr;
p = variables.Next(p)) {
const AstRawString* name = static_cast<const AstRawString*>(p->key);
Variable* var = LookupLocal(name);
if (var != nullptr) { if (var != nullptr) {
// Conflict; find and return its declaration. // Conflict; find and return its declaration.
DCHECK(IsLexicalVariableMode(var->mode())); DCHECK(IsLexicalVariableMode(var->mode()));
const AstRawString* name = names.at(i); return name;
for (Declaration* decl : decls_) {
if (decl->proxy()->raw_name() == name) return decl;
}
DCHECK(false);
} }
} }
return nullptr; return nullptr;
} }
Declaration* Scope::DeclarationFor(const AstRawString* name) {
for (Declaration* decl : decls_) {
if (decl->proxy()->raw_name() == name) return decl;
}
UNREACHABLE();
}
bool DeclarationScope::AllocateVariables(ParseInfo* info) { bool DeclarationScope::AllocateVariables(ParseInfo* info) {
// Module variables must be allocated before variable resolution // Module variables must be allocated before variable resolution
// to ensure that UpdateNeedsHoleCheck() can detect import variables. // to ensure that UpdateNeedsHoleCheck() can detect import variables.
......
...@@ -258,7 +258,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -258,7 +258,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// The return value is meaningful only if FLAG_preparser_scope_analysis is on. // The return value is meaningful only if FLAG_preparser_scope_analysis is on.
Variable* DeclareVariableName(const AstRawString* name, VariableMode mode); Variable* DeclareVariableName(const AstRawString* name, VariableMode mode);
void DeclareCatchVariableName(const AstRawString* name); Variable* DeclareCatchVariableName(const AstRawString* name);
// Declarations list. // Declarations list.
base::ThreadedList<Declaration>* declarations() { return &decls_; } base::ThreadedList<Declaration>* declarations() { return &decls_; }
...@@ -312,13 +312,14 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -312,13 +312,14 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// scope over a let binding of the same name. // scope over a let binding of the same name.
Declaration* CheckConflictingVarDeclarations(); Declaration* CheckConflictingVarDeclarations();
// Check if the scope has a conflicting lexical declaration that has a name in // Find lexical variable that has a name that was declared in |scope|. This is
// the given list. This is used to catch patterns like // used to catch patterns like `try{}catch(e){let e;}`, which is an error even
// `try{}catch(e){let e;}`, // though the two 'e's are declared in different scopes. Returns the first
// which is an error even though the two 'e's are declared in different // duplicate variable name if there is one, nullptr otherwise.
// scopes. const AstRawString* FindLexVariableDeclaredIn(Scope* scope);
Declaration* CheckLexDeclarationsConflictingWith(
const ZonePtrList<const AstRawString>& names); // Find the declaration that introduced |name|.
Declaration* DeclarationFor(const AstRawString* name);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Scope-specific info. // Scope-specific info.
......
...@@ -519,18 +519,12 @@ class ParserBase { ...@@ -519,18 +519,12 @@ class ParserBase {
struct CatchInfo { struct CatchInfo {
public: public:
explicit CatchInfo(ParserBase* parser) explicit CatchInfo(ParserBase* parser)
: name(parser->impl()->NullIdentifier()), : pattern(parser->impl()->NullExpression()),
pattern(parser->impl()->NullExpression()), variable(nullptr),
scope(nullptr), scope(nullptr) {}
init_block(parser->impl()->NullStatement()),
inner_block(parser->impl()->NullStatement()),
bound_names(1, parser->zone()) {}
IdentifierT name;
ExpressionT pattern; ExpressionT pattern;
Variable* variable;
Scope* scope; Scope* scope;
BlockT init_block;
BlockT inner_block;
ZonePtrList<const AstRawString> bound_names;
}; };
struct ForInfo { struct ForInfo {
...@@ -3515,7 +3509,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( ...@@ -3515,7 +3509,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
parsing_result->descriptor.declaration_pos = peek_position(); parsing_result->descriptor.declaration_pos = peek_position();
parsing_result->descriptor.initialization_pos = peek_position(); parsing_result->descriptor.initialization_pos = peek_position();
BlockT init_block = impl()->NullStatement(); BlockT init_block = impl()->NullBlock();
if (var_context != kForStatement) { if (var_context != kForStatement) {
init_block = factory()->NewBlock(1, true); init_block = factory()->NewBlock(1, true);
} }
...@@ -3611,7 +3605,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( ...@@ -3611,7 +3605,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
Scanner::Location(decl_pos, end_position()), Scanner::Location(decl_pos, end_position()),
MessageTemplate::kDeclarationMissingInitializer, MessageTemplate::kDeclarationMissingInitializer,
!impl()->IsIdentifier(pattern) ? "destructuring" : "const"); !impl()->IsIdentifier(pattern) ? "destructuring" : "const");
return impl()->NullStatement(); return impl()->NullBlock();
} }
// 'let x' initializes 'x' to undefined. // 'let x' initializes 'x' to undefined.
if (parsing_result->descriptor.mode == VariableMode::kLet) { if (parsing_result->descriptor.mode == VariableMode::kLet) {
...@@ -4234,7 +4228,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( ...@@ -4234,7 +4228,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
template <typename Impl> template <typename Impl>
void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope,
StatementListT* body) { StatementListT* body) {
BlockT block = impl()->NullStatement(); BlockT block = impl()->NullBlock();
{ {
StatementListT statements(pointer_buffer()); StatementListT statements(pointer_buffer());
ParseStatementList(&statements, Token::RBRACE); ParseStatementList(&statements, Token::RBRACE);
...@@ -4736,19 +4730,19 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( ...@@ -4736,19 +4730,19 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
// Block :: // Block ::
// '{' StatementList '}' // '{' StatementList '}'
// Parse the statements and collect escaping labels.
BlockT body = factory()->NewBlock(false, labels); BlockT body = factory()->NewBlock(false, labels);
StatementListT statements(pointer_buffer()); StatementListT statements(pointer_buffer());
// Parse the statements and collect escaping labels.
Expect(Token::LBRACE);
CheckStackOverflow(); CheckStackOverflow();
{ {
BlockState block_state(zone(), &scope_); BlockState block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos); scope()->set_start_position(peek_position());
TargetT target(this, body); TargetT target(this, body);
Expect(Token::LBRACE);
while (peek() != Token::RBRACE) { while (peek() != Token::RBRACE) {
StatementT stat = ParseStatementListItem(); StatementT stat = ParseStatementListItem();
if (impl()->IsNull(stat)) return body; if (impl()->IsNull(stat)) return body;
...@@ -4757,6 +4751,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( ...@@ -4757,6 +4751,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
} }
Expect(Token::RBRACE); Expect(Token::RBRACE);
int end_pos = end_position(); int end_pos = end_position();
scope()->set_end_position(end_pos); scope()->set_end_position(end_pos);
...@@ -5255,7 +5250,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() { ...@@ -5255,7 +5250,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() {
SourceRange catch_range, finally_range; SourceRange catch_range, finally_range;
BlockT catch_block = impl()->NullStatement(); BlockT catch_block = impl()->NullBlock();
{ {
SourceRangeScope catch_range_scope(scanner(), &catch_range); SourceRangeScope catch_range_scope(scanner(), &catch_range);
if (Check(Token::CATCH)) { if (Check(Token::CATCH)) {
...@@ -5274,31 +5269,44 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() { ...@@ -5274,31 +5269,44 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() {
// as part of destructuring the catch parameter. // as part of destructuring the catch parameter.
{ {
BlockState catch_variable_block_state(zone(), &scope_); BlockState catch_variable_block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos); scope()->set_start_position(position());
// This does not simply call ParsePrimaryExpression to avoid
// ExpressionFromIdentifier from being called in the first
// branch, which would introduce an unresolved symbol and mess
// with arrow function names.
if (peek_any_identifier()) { if (peek_any_identifier()) {
catch_info.name = ParseNonRestrictedIdentifier(); IdentifierT identifier = ParseNonRestrictedIdentifier();
RETURN_IF_PARSE_ERROR;
catch_info.variable = impl()->DeclareCatchVariableName(
catch_info.scope, identifier);
} else { } else {
DeclarationParsingScope declaration( catch_info.variable = catch_info.scope->DeclareCatchVariableName(
impl(), ExpressionScope::kVarDeclaration); ast_value_factory()->dot_catch_string());
DeclarationParsingScope destructuring(
impl(), ExpressionScope::kLexicalDeclaration);
catch_info.pattern = ParseBindingPattern(); catch_info.pattern = ParseBindingPattern();
RETURN_IF_PARSE_ERROR;
catch_statements.Add(impl()->RewriteCatchPattern(&catch_info));
} }
Expect(Token::RPAREN); Expect(Token::RPAREN);
RETURN_IF_PARSE_ERROR;
impl()->RewriteCatchPattern(&catch_info); BlockT inner_block = ParseBlock(nullptr);
if (!impl()->IsNull(catch_info.init_block)) { catch_statements.Add(inner_block);
catch_statements.Add(catch_info.init_block);
// Check for `catch(e) { let e; }` and similar errors.
Scope* inner_scope = inner_block->scope();
if (inner_scope != nullptr) {
const AstRawString* conflict = nullptr;
if (impl()->IsNull(catch_info.pattern)) {
const AstRawString* name = catch_info.variable->raw_name();
if (inner_scope->LookupLocal(name)) conflict = name;
} else {
conflict = inner_scope->FindLexVariableDeclaredIn(scope());
}
if (conflict != nullptr) {
impl()->ReportConflictingDeclarationInCatch(conflict,
inner_scope);
}
} }
catch_info.inner_block = ParseBlock(nullptr);
catch_statements.Add(catch_info.inner_block);
RETURN_IF_PARSE_ERROR;
impl()->ValidateCatchBlock(catch_info);
scope()->set_end_position(end_position()); scope()->set_end_position(end_position());
catch_block = factory()->NewBlock(false, catch_statements); catch_block = factory()->NewBlock(false, catch_statements);
catch_block->set_scope(scope()->FinalizeBlockScope()); catch_block->set_scope(scope()->FinalizeBlockScope());
...@@ -5312,7 +5320,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() { ...@@ -5312,7 +5320,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() {
} }
} }
BlockT finally_block = impl()->NullStatement(); BlockT finally_block = impl()->NullBlock();
DCHECK(has_error() || peek() == Token::FINALLY || DCHECK(has_error() || peek() == Token::FINALLY ||
!impl()->IsNull(catch_block)); !impl()->IsNull(catch_block));
{ {
...@@ -5499,7 +5507,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( ...@@ -5499,7 +5507,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
} }
ExpressionT each_variable = impl()->NullExpression(); ExpressionT each_variable = impl()->NullExpression();
BlockT body_block = impl()->NullStatement(); BlockT body_block = impl()->NullBlock();
{ {
BlockState block_state( BlockState block_state(
&scope_, inner_block_scope != nullptr ? inner_block_scope : scope_); &scope_, inner_block_scope != nullptr ? inner_block_scope : scope_);
...@@ -5777,7 +5785,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -5777,7 +5785,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
impl()->RecordIterationStatementSourceRange(loop, body_range); impl()->RecordIterationStatementSourceRange(loop, body_range);
if (has_declarations) { if (has_declarations) {
BlockT body_block = impl()->NullStatement(); BlockT body_block = impl()->NullBlock();
impl()->DesugarBindingInForEachStatement(&for_info, &body_block, impl()->DesugarBindingInForEachStatement(&for_info, &body_block,
&each_variable); &each_variable);
body_block->statements()->Add(body, zone()); body_block->statements()->Add(body, zone());
...@@ -5802,7 +5810,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -5802,7 +5810,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
} }
BlockT init_block = BlockT init_block =
impl()->CreateForEachStatementTDZ(impl()->NullStatement(), for_info); impl()->CreateForEachStatementTDZ(impl()->NullBlock(), for_info);
scope()->set_end_position(end_position()); scope()->set_end_position(end_position());
Scope* for_scope = scope()->FinalizeBlockScope(); Scope* for_scope = scope()->FinalizeBlockScope();
......
...@@ -1568,52 +1568,41 @@ Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement, ...@@ -1568,52 +1568,41 @@ Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement,
return switch_block; return switch_block;
} }
void Parser::RewriteCatchPattern(CatchInfo* catch_info) { Block* Parser::RewriteCatchPattern(CatchInfo* catch_info) {
if (catch_info->name == nullptr) { DCHECK_NOT_NULL(catch_info->pattern);
DCHECK_NOT_NULL(catch_info->pattern); DeclarationDescriptor descriptor;
catch_info->name = ast_value_factory()->dot_catch_string(); descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
} descriptor.scope = scope();
Variable* catch_variable = descriptor.mode = VariableMode::kLet;
catch_info->scope->DeclareLocal(catch_info->name, VariableMode::kVar); descriptor.declaration_pos = catch_info->pattern->position();
if (catch_info->pattern != nullptr) { descriptor.initialization_pos = catch_info->pattern->position();
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::NORMAL; // Initializer position for variables declared by the pattern.
descriptor.scope = scope(); const int initializer_position = position();
descriptor.mode = VariableMode::kLet;
descriptor.declaration_pos = catch_info->pattern->position(); DeclarationParsingResult::Declaration decl(
descriptor.initialization_pos = catch_info->pattern->position(); catch_info->pattern, initializer_position,
factory()->NewVariableProxy(catch_info->variable));
// Initializer position for variables declared by the pattern.
const int initializer_position = position(); Block* init_block = factory()->NewBlock(8, true);
DeclareAndInitializeVariables(init_block, &descriptor, &decl, nullptr);
DeclarationParsingResult::Declaration decl( return init_block;
catch_info->pattern, initializer_position,
factory()->NewVariableProxy(catch_variable));
catch_info->init_block = factory()->NewBlock(8, true);
DeclareAndInitializeVariables(catch_info->init_block, &descriptor, &decl,
&catch_info->bound_names);
} else {
catch_info->bound_names.Add(catch_info->name, zone());
}
} }
void Parser::ValidateCatchBlock(const CatchInfo& catch_info) { void Parser::ReportConflictingDeclarationInCatch(const AstRawString* name,
// Check for `catch(e) { let e; }` and similar errors. Scope* scope) {
Scope* inner_block_scope = catch_info.inner_block->scope(); for (Declaration* decl : *scope->declarations()) {
if (inner_block_scope != nullptr) { if (decl->proxy()->raw_name() == name) {
Declaration* decl = inner_block_scope->CheckLexDeclarationsConflictingWith(
catch_info.bound_names);
if (decl != nullptr) {
const AstRawString* name = decl->proxy()->raw_name();
int position = decl->proxy()->position(); int position = decl->proxy()->position();
Scanner::Location location = Scanner::Location location =
position == kNoSourcePosition position == kNoSourcePosition
? Scanner::Location::invalid() ? Scanner::Location::invalid()
: Scanner::Location(position, position + 1); : Scanner::Location(position, position + name->length());
ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name); ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
return;
} }
} }
UNREACHABLE();
} }
Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block, Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
......
...@@ -317,8 +317,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -317,8 +317,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* RewriteReturn(Expression* return_value, int pos); Expression* RewriteReturn(Expression* return_value, int pos);
Statement* RewriteSwitchStatement(SwitchStatement* switch_statement, Statement* RewriteSwitchStatement(SwitchStatement* switch_statement,
Scope* scope); Scope* scope);
void RewriteCatchPattern(CatchInfo* catch_info); Block* RewriteCatchPattern(CatchInfo* catch_info);
void ValidateCatchBlock(const CatchInfo& catch_info); void ReportConflictingDeclarationInCatch(const AstRawString* name,
Scope* scope);
Statement* RewriteTryStatement(Block* try_block, Block* catch_block, Statement* RewriteTryStatement(Block* try_block, Block* catch_block,
const SourceRange& catch_range, const SourceRange& catch_range,
Block* finally_block, Block* finally_block,
...@@ -830,6 +831,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -830,6 +831,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return nullptr; return nullptr;
} }
V8_INLINE static std::nullptr_t NullStatement() { return nullptr; } V8_INLINE static std::nullptr_t NullStatement() { return nullptr; }
V8_INLINE static std::nullptr_t NullBlock() { return nullptr; }
Expression* FailureExpression() { return factory()->FailureExpression(); } Expression* FailureExpression() { return factory()->FailureExpression(); }
template <typename T> template <typename T>
...@@ -881,6 +883,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -881,6 +883,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return NewUnresolved(name, start_position); return NewUnresolved(name, start_position);
} }
V8_INLINE Variable* DeclareCatchVariableName(Scope* scope,
const AstRawString* name) {
return scope->DeclareCatchVariableName(name);
}
V8_INLINE ZonePtrList<Expression>* NewExpressionList(int size) const { V8_INLINE ZonePtrList<Expression>* NewExpressionList(int size) const {
return new (zone()) ZonePtrList<Expression>(size, zone()); return new (zone()) ZonePtrList<Expression>(size, zone());
} }
......
...@@ -381,7 +381,7 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( ...@@ -381,7 +381,7 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
return kLazyParsingComplete; return kLazyParsingComplete;
} }
PreParserStatement PreParser::BuildParameterInitializationBlock( PreParserBlock PreParser::BuildParameterInitializationBlock(
const PreParserFormalParameters& parameters) { const PreParserFormalParameters& parameters) {
DCHECK(!parameters.is_simple); DCHECK(!parameters.is_simple);
DCHECK(scope()->is_function_scope()); DCHECK(scope()->is_function_scope());
...@@ -402,7 +402,7 @@ PreParserStatement PreParser::BuildParameterInitializationBlock( ...@@ -402,7 +402,7 @@ PreParserStatement PreParser::BuildParameterInitializationBlock(
} }
} }
return PreParserStatement::Default(); return PreParserBlock::Default();
} }
bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier, bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier,
......
...@@ -524,7 +524,7 @@ class PreParserStatement { ...@@ -524,7 +524,7 @@ class PreParserStatement {
PreParserStatement next, PreParserStatement body, PreParserStatement next, PreParserStatement body,
const SourceRange& body_range = {}) {} const SourceRange& body_range = {}) {}
private: protected:
enum Type { enum Type {
kNullStatement, kNullStatement,
kEmptyStatement, kEmptyStatement,
...@@ -534,9 +534,32 @@ class PreParserStatement { ...@@ -534,9 +534,32 @@ class PreParserStatement {
}; };
explicit PreParserStatement(Type code) : code_(code) {} explicit PreParserStatement(Type code) : code_(code) {}
private:
Type code_; Type code_;
}; };
// A PreParserBlock extends statement with a place to store the scope.
// The scope is dropped as the block is returned as a statement.
class PreParserBlock : public PreParserStatement {
public:
void set_scope(Scope* scope) { scope_ = scope; }
Scope* scope() const { return scope_; }
static PreParserBlock Default() {
return PreParserBlock(PreParserStatement::kUnknownStatement);
}
static PreParserBlock Null() {
return PreParserBlock(PreParserStatement::kNullStatement);
}
// Dummy implementation for making block->somefunc() work in both Parser and
// PreParser.
PreParserBlock* operator->() { return this; }
private:
explicit PreParserBlock(PreParserStatement::Type type)
: PreParserStatement(type), scope_(nullptr) {}
Scope* scope_;
};
class PreParserFactory { class PreParserFactory {
public: public:
...@@ -722,18 +745,18 @@ class PreParserFactory { ...@@ -722,18 +745,18 @@ class PreParserFactory {
PreParserStatement EmptyStatement() { return PreParserStatement::Default(); } PreParserStatement EmptyStatement() { return PreParserStatement::Default(); }
PreParserStatement NewBlock(int capacity, bool ignore_completion_value) { PreParserBlock NewBlock(int capacity, bool ignore_completion_value) {
return PreParserStatement::Default(); return PreParserBlock::Default();
} }
PreParserStatement NewBlock(bool ignore_completion_value, PreParserBlock NewBlock(bool ignore_completion_value,
ZonePtrList<const AstRawString>* labels) { ZonePtrList<const AstRawString>* labels) {
return PreParserStatement::Default(); return PreParserBlock::Default();
} }
PreParserStatement NewBlock(bool ignore_completion_value, PreParserBlock NewBlock(bool ignore_completion_value,
const PreParserScopedStatementList& list) { const PreParserScopedStatementList& list) {
return PreParserStatement::Default(); return PreParserBlock::Default();
} }
PreParserStatement NewDebuggerStatement(int pos) { PreParserStatement NewDebuggerStatement(int pos) {
...@@ -927,7 +950,7 @@ struct ParserTypes<PreParser> { ...@@ -927,7 +950,7 @@ struct ParserTypes<PreParser> {
typedef PreParserIdentifier Identifier; typedef PreParserIdentifier Identifier;
typedef PreParserPropertyList ClassPropertyList; typedef PreParserPropertyList ClassPropertyList;
typedef PreParserScopedStatementList StatementList; typedef PreParserScopedStatementList StatementList;
typedef PreParserStatement Block; typedef PreParserBlock Block;
typedef PreParserStatement BreakableStatement; typedef PreParserStatement BreakableStatement;
typedef PreParserStatement ForStatement; typedef PreParserStatement ForStatement;
typedef PreParserStatement IterationStatement; typedef PreParserStatement IterationStatement;
...@@ -1131,21 +1154,20 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1131,21 +1154,20 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
V8_INLINE void RewriteCatchPattern(CatchInfo* catch_info) { V8_INLINE PreParserBlock RewriteCatchPattern(CatchInfo* catch_info) {
const AstRawString* catch_name = catch_info->name.string_;
if (catch_name == nullptr) {
catch_name = ast_value_factory()->dot_catch_string();
}
catch_info->scope->DeclareCatchVariableName(catch_name);
if (catch_info->pattern.variables_ != nullptr) { if (catch_info->pattern.variables_ != nullptr) {
for (auto variable : *catch_info->pattern.variables_) { for (auto variable : *catch_info->pattern.variables_) {
scope()->DeclareVariableName(variable->raw_name(), VariableMode::kLet); scope()->DeclareVariableName(variable->raw_name(), VariableMode::kLet);
} }
} }
return PreParserBlock::Default();
}
V8_INLINE void ReportConflictingDeclarationInCatch(const AstRawString* name,
Scope* scope) {
ReportUnidentifiableError();
} }
V8_INLINE void ValidateCatchBlock(const CatchInfo& catch_info) {}
V8_INLINE PreParserStatement RewriteTryStatement( V8_INLINE PreParserStatement RewriteTryStatement(
PreParserStatement try_block, PreParserStatement catch_block, PreParserStatement try_block, PreParserStatement catch_block,
const SourceRange& catch_range, PreParserStatement finally_block, const SourceRange& catch_range, PreParserStatement finally_block,
...@@ -1447,8 +1469,8 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1447,8 +1469,8 @@ class PreParser : public ParserBase<PreParser> {
return stmt; return stmt;
} }
V8_INLINE PreParserStatement RewriteForVarInLegacy(const ForInfo& for_info) { V8_INLINE PreParserBlock RewriteForVarInLegacy(const ForInfo& for_info) {
return PreParserStatement::Null(); return PreParserBlock::Null();
} }
V8_INLINE void DesugarBindingInForEachStatement( V8_INLINE void DesugarBindingInForEachStatement(
...@@ -1468,13 +1490,13 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1468,13 +1490,13 @@ class PreParser : public ParserBase<PreParser> {
collect_names ? &for_info->bound_names : nullptr); collect_names ? &for_info->bound_names : nullptr);
} }
V8_INLINE PreParserStatement CreateForEachStatementTDZ( V8_INLINE PreParserBlock CreateForEachStatementTDZ(PreParserBlock init_block,
PreParserStatement init_block, const ForInfo& for_info) { const ForInfo& for_info) {
if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) { if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
for (auto name : for_info.bound_names) { for (auto name : for_info.bound_names) {
scope()->DeclareVariableName(name, VariableMode::kLet); scope()->DeclareVariableName(name, VariableMode::kLet);
} }
return PreParserStatement::Default(); return PreParserBlock::Default();
} }
return init_block; return init_block;
} }
...@@ -1491,12 +1513,12 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1491,12 +1513,12 @@ class PreParser : public ParserBase<PreParser> {
return loop; return loop;
} }
PreParserStatement BuildParameterInitializationBlock( PreParserBlock BuildParameterInitializationBlock(
const PreParserFormalParameters& parameters); const PreParserFormalParameters& parameters);
V8_INLINE PreParserStatement V8_INLINE PreParserBlock
BuildRejectPromiseOnException(PreParserStatement init_block) { BuildRejectPromiseOnException(PreParserStatement init_block) {
return PreParserStatement::Default(); return PreParserBlock::Default();
} }
V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) { V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
...@@ -1562,6 +1584,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1562,6 +1584,7 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE static PreParserStatement NullStatement() { V8_INLINE static PreParserStatement NullStatement() {
return PreParserStatement::Null(); return PreParserStatement::Null();
} }
V8_INLINE static PreParserBlock NullBlock() { return PreParserBlock::Null(); }
template <typename T> template <typename T>
V8_INLINE static bool IsNull(T subject) { V8_INLINE static bool IsNull(T subject) {
...@@ -1631,6 +1654,11 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1631,6 +1654,11 @@ class PreParser : public ParserBase<PreParser> {
const PreParserIdentifier& name, int start_position, const PreParserIdentifier& name, int start_position,
InferName infer = InferName::kYes); InferName infer = InferName::kYes);
V8_INLINE Variable* DeclareCatchVariableName(
Scope* scope, const PreParserIdentifier& identifier) {
return scope->DeclareCatchVariableName(identifier.string_);
}
V8_INLINE PreParserPropertyList NewClassPropertyList(int size) const { V8_INLINE PreParserPropertyList NewClassPropertyList(int size) const {
return PreParserPropertyList(); return PreParserPropertyList();
} }
......
// Copyright 2018 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.
function f() {
try { }
catch ({x}) {
let x
}
}
*%(basename)s:8: SyntaxError: Identifier 'x' has already been declared
let x
^
SyntaxError: Identifier 'x' has already been declared
// Copyright 2018 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.
function f1() {
let y = 200;
try {
throw {}
} catch ({x=()=>y, y=300}) {
return x()
}
}
assertEquals(300, f1());
function f2() {
let y = 200;
try {
throw {}
} catch ({x=()=>y}) {
let y = 300;
return x()
}
}
assertEquals(200, f2());
...@@ -406,9 +406,6 @@ ...@@ -406,9 +406,6 @@
'language/literals/regexp/u-unicode-esc-non-hex': [FAIL_PHASE_ONLY], 'language/literals/regexp/u-unicode-esc-non-hex': [FAIL_PHASE_ONLY],
'language/literals/regexp/unicode-escape-nls-err': [FAIL_PHASE_ONLY], 'language/literals/regexp/unicode-escape-nls-err': [FAIL_PHASE_ONLY],
# https://bugs.chromium.org/p/v8/issues/detail?id=7828
'language/statements/try/early-catch-function': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7829 # https://bugs.chromium.org/p/v8/issues/detail?id=7829
'language/block-scope/syntax/redeclaration/function-declaration-attempt-to-redeclare-with-var-declaration-nested-in-function': [FAIL], 'language/block-scope/syntax/redeclaration/function-declaration-attempt-to-redeclare-with-var-declaration-nested-in-function': [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