Commit 5a72c6b6 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[parser] Use Token::INIT for hoisted sloppy block functions when possible

Change-Id: I83dc3bed644361be1b94063daefd890b10ba50cd
Reviewed-on: https://chromium-review.googlesource.com/c/1433772
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59095}
parent 592aeefa
...@@ -491,26 +491,14 @@ inline NestedVariableDeclaration* VariableDeclaration::AsNested() { ...@@ -491,26 +491,14 @@ inline NestedVariableDeclaration* VariableDeclaration::AsNested() {
class FunctionDeclaration final : public Declaration { class FunctionDeclaration final : public Declaration {
public: public:
FunctionLiteral* fun() const { return fun_; } FunctionLiteral* fun() const { return fun_; }
bool declares_sloppy_block_function() const {
return DeclaresSloppyBlockFunction::decode(bit_field_);
}
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
class DeclaresSloppyBlockFunction FunctionDeclaration(FunctionLiteral* fun, int pos)
: public BitField<bool, Declaration::kNextBitFieldIndex, 1> {}; : Declaration(pos, kFunctionDeclaration), fun_(fun) {}
FunctionDeclaration(FunctionLiteral* fun, bool declares_sloppy_block_function,
int pos)
: Declaration(pos, kFunctionDeclaration), fun_(fun) {
bit_field_ = DeclaresSloppyBlockFunction::update(
bit_field_, declares_sloppy_block_function);
}
FunctionLiteral* fun_; FunctionLiteral* fun_;
static const uint8_t kNextBitFieldIndex = DeclaresSloppyBlockFunction::kNext;
}; };
...@@ -994,14 +982,30 @@ class SloppyBlockFunctionStatement final : public Statement { ...@@ -994,14 +982,30 @@ class SloppyBlockFunctionStatement final : public Statement {
public: public:
Statement* statement() const { return statement_; } Statement* statement() const { return statement_; }
void set_statement(Statement* statement) { statement_ = statement; } void set_statement(Statement* statement) { statement_ = statement; }
Scope* scope() const { return var_->scope(); }
Variable* var() const { return var_; }
Token::Value init() const { return TokenField::decode(bit_field_); }
const AstRawString* name() const { return var_->raw_name(); }
SloppyBlockFunctionStatement** next() { return &next_; }
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
SloppyBlockFunctionStatement(int pos, Statement* statement) class TokenField
: Statement(pos, kSloppyBlockFunctionStatement), statement_(statement) {} : public BitField<Token::Value, Statement::kNextBitFieldIndex, 8> {};
SloppyBlockFunctionStatement(int pos, Variable* var, Token::Value init,
Statement* statement)
: Statement(pos, kSloppyBlockFunctionStatement),
var_(var),
statement_(statement),
next_(nullptr) {
bit_field_ = TokenField::update(bit_field_, init);
}
Variable* var_;
Statement* statement_; Statement* statement_;
SloppyBlockFunctionStatement* next_;
}; };
...@@ -2812,10 +2816,8 @@ class AstNodeFactory final { ...@@ -2812,10 +2816,8 @@ class AstNodeFactory final {
return new (zone_) NestedVariableDeclaration(scope, pos); return new (zone_) NestedVariableDeclaration(scope, pos);
} }
FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun, FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun, int pos) {
bool is_sloppy_block_function, return new (zone_) FunctionDeclaration(fun, pos);
int pos) {
return new (zone_) FunctionDeclaration(fun, is_sloppy_block_function, pos);
} }
Block* NewBlock(int capacity, bool ignore_completion_value) { Block* NewBlock(int capacity, bool ignore_completion_value) {
...@@ -2958,8 +2960,10 @@ class AstNodeFactory final { ...@@ -2958,8 +2960,10 @@ class AstNodeFactory final {
return failure_expression_; return failure_expression_;
} }
SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(int pos) { SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(
return new (zone_) SloppyBlockFunctionStatement(pos, EmptyStatement()); int pos, Variable* var, Token::Value init) {
return new (zone_)
SloppyBlockFunctionStatement(pos, var, init, EmptyStatement());
} }
CaseClause* NewCaseClause(Expression* label, CaseClause* NewCaseClause(Expression* label,
......
...@@ -83,28 +83,6 @@ Variable* VariableMap::Lookup(const AstRawString* name) { ...@@ -83,28 +83,6 @@ Variable* VariableMap::Lookup(const AstRawString* name) {
return nullptr; return nullptr;
} }
void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) {
if (statement_ != nullptr) {
statement_->set_statement(statement);
}
}
SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
: ZoneHashMap(8, ZoneAllocationPolicy(zone)), count_(0) {}
void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name,
Scope* scope,
SloppyBlockFunctionStatement* statement) {
auto* delegate = new (zone) Delegate(scope, statement, count_++);
// AstRawStrings are unambiguous, i.e., the same string is always represented
// by the same AstRawString*.
Entry* p =
ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->Hash(),
ZoneAllocationPolicy(zone));
delegate->set_next(static_cast<SloppyBlockFunctionMap::Delegate*>(p->value));
p->value = delegate;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation of Scope // Implementation of Scope
...@@ -263,7 +241,6 @@ void DeclarationScope::SetDefaults() { ...@@ -263,7 +241,6 @@ void DeclarationScope::SetDefaults() {
has_arguments_parameter_ = false; has_arguments_parameter_ = false;
scope_uses_super_property_ = false; scope_uses_super_property_ = false;
has_rest_ = false; has_rest_ = false;
sloppy_block_function_map_ = nullptr;
receiver_ = nullptr; receiver_ = nullptr;
new_target_ = nullptr; new_target_ = nullptr;
function_ = nullptr; function_ = nullptr;
...@@ -456,14 +433,8 @@ int Scope::num_parameters() const { ...@@ -456,14 +433,8 @@ int Scope::num_parameters() const {
} }
void DeclarationScope::DeclareSloppyBlockFunction( void DeclarationScope::DeclareSloppyBlockFunction(
const AstRawString* name, Scope* scope, SloppyBlockFunctionStatement* sloppy_block_function) {
SloppyBlockFunctionStatement* statement) { sloppy_block_functions_.Add(sloppy_block_function);
if (sloppy_block_function_map_ == nullptr) {
sloppy_block_function_map_ =
new (zone()->New(sizeof(SloppyBlockFunctionMap)))
SloppyBlockFunctionMap(zone());
}
sloppy_block_function_map_->Declare(zone(), name, scope, statement);
} }
void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
...@@ -473,8 +444,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { ...@@ -473,8 +444,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_); DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_); DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);
SloppyBlockFunctionMap* map = sloppy_block_function_map(); if (sloppy_block_functions_.is_empty()) return;
if (map == nullptr) return;
// In case of complex parameters the current scope is the body scope and the // In case of complex parameters the current scope is the body scope and the
// parameters are stored in the outer scope. // parameters are stored in the outer scope.
...@@ -482,14 +452,17 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { ...@@ -482,14 +452,17 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
DCHECK(parameter_scope->is_function_scope() || is_eval_scope() || DCHECK(parameter_scope->is_function_scope() || is_eval_scope() ||
is_script_scope()); is_script_scope());
// The declarations need to be added in the order they were seen, DeclarationScope* decl_scope = this;
// so accumulate declared names sorted by index. while (decl_scope->is_eval_scope()) {
ZoneMap<int, const AstRawString*> names_to_declare(zone()); decl_scope = decl_scope->outer_scope()->GetDeclarationScope();
}
Scope* outer_scope = decl_scope->outer_scope();
// For each variable which is used as a function declaration in a sloppy // For each variable which is used as a function declaration in a sloppy
// block, // block,
for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { for (SloppyBlockFunctionStatement* sloppy_block_function :
const AstRawString* name = static_cast<AstRawString*>(p->key); sloppy_block_functions_) {
const AstRawString* name = sloppy_block_function->name();
// If the variable wouldn't conflict with a lexical declaration // If the variable wouldn't conflict with a lexical declaration
// or parameter, // or parameter,
...@@ -500,26 +473,11 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { ...@@ -500,26 +473,11 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
continue; continue;
} }
bool declaration_queued = false;
// Write in assignments to var for each block-scoped function declaration
auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value);
DeclarationScope* decl_scope = this;
while (decl_scope->is_eval_scope()) {
decl_scope = decl_scope->outer_scope()->GetDeclarationScope();
}
Scope* outer_scope = decl_scope->outer_scope();
for (SloppyBlockFunctionMap::Delegate* delegate = delegates;
delegate != nullptr; delegate = delegate->next()) {
// Check if there's a conflict with a lexical declaration // Check if there's a conflict with a lexical declaration
Scope* query_scope = delegate->scope()->outer_scope(); Scope* query_scope = sloppy_block_function->scope()->outer_scope();
Variable* var = nullptr; Variable* var = nullptr;
bool should_hoist = true; bool should_hoist = true;
// Note that we perform this loop for each delegate named 'name',
// which may duplicate work if those delegates share scopes.
// It is not sufficient to just do a Lookup on query_scope: for // It is not sufficient to just do a Lookup on query_scope: for
// example, that does not prevent hoisting of the function in // example, that does not prevent hoisting of the function in
// `{ let e; try {} catch (e) { function e(){} } }` // `{ let e; try {} catch (e) { function e(){} } }`
...@@ -534,44 +492,32 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { ...@@ -534,44 +492,32 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
if (!should_hoist) continue; if (!should_hoist) continue;
if (!declaration_queued) {
declaration_queued = true;
names_to_declare.insert({delegate->index(), name});
}
if (factory) {
DCHECK(!is_being_lazily_parsed_);
int pos = delegate->position();
Assignment* assignment = factory->NewAssignment(
Token::ASSIGN, NewUnresolved(factory, name, pos),
delegate->scope()->NewUnresolved(factory, name, pos), pos);
assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
Statement* statement = factory->NewExpressionStatement(assignment, pos);
delegate->set_statement(statement);
}
}
}
if (names_to_declare.empty()) return;
for (const auto& index_and_name : names_to_declare) {
const AstRawString* name = index_and_name.second;
if (factory) { if (factory) {
DCHECK(!is_being_lazily_parsed_); DCHECK(!is_being_lazily_parsed_);
auto declaration = factory->NewVariableDeclaration(kNoSourcePosition); int pos = sloppy_block_function->position();
bool ok = true;
bool was_added; bool was_added;
auto declaration = factory->NewVariableDeclaration(pos);
// Based on the preceding checks, it doesn't matter what we pass as // Based on the preceding checks, it doesn't matter what we pass as
// sloppy_mode_block_scope_function_redefinition. // sloppy_mode_block_scope_function_redefinition.
bool ok = true; Variable* var = DeclareVariable(
DeclareVariable(declaration, name, kNoSourcePosition, VariableMode::kVar, declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE,
NORMAL_VARIABLE, Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added,
Variable::DefaultInitializationFlag(VariableMode::kVar), nullptr, &ok);
&was_added, nullptr, &ok);
DCHECK(ok); DCHECK(ok);
VariableProxy* source =
factory->NewVariableProxy(sloppy_block_function->var());
VariableProxy* target = factory->NewVariableProxy(var);
Assignment* assignment = factory->NewAssignment(
sloppy_block_function->init(), target, source, pos);
assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
Statement* statement = factory->NewExpressionStatement(assignment, pos);
sloppy_block_function->set_statement(statement);
} else { } else {
DCHECK(is_being_lazily_parsed_); DCHECK(is_being_lazily_parsed_);
bool was_added; bool was_added;
Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added); Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
if (sloppy_block_function->init() == Token::ASSIGN)
var->set_maybe_assigned(); var->set_maybe_assigned();
} }
} }
...@@ -1029,16 +975,9 @@ Variable* Scope::DeclareVariable( ...@@ -1029,16 +975,9 @@ Variable* Scope::DeclareVariable(
// In harmony we treat re-declarations as early errors. See ES5 16 for a // In harmony we treat re-declarations as early errors. See ES5 16 for a
// definition of early errors. // definition of early errors.
// //
// Allow duplicate function decls for web compat, see bug 4693. If the // Allow duplicate function decls for web compat, see bug 4693.
// duplication is allowed, then the var will show up in the *ok = var->is_sloppy_block_function() &&
// SloppyBlockFunctionMap. kind == SLOPPY_BLOCK_FUNCTION_VARIABLE;
SloppyBlockFunctionMap* map =
GetDeclarationScope()->sloppy_block_function_map();
*ok =
map != nullptr && declaration->IsFunctionDeclaration() &&
declaration->AsFunctionDeclaration()
->declares_sloppy_block_function() &&
map->Lookup(const_cast<AstRawString*>(name), name->Hash()) != nullptr;
*sloppy_mode_block_scope_function_redefinition = *ok; *sloppy_mode_block_scope_function_redefinition = *ok;
} }
} }
...@@ -1078,12 +1017,16 @@ Variable* Scope::DeclareVariableName(const AstRawString* name, ...@@ -1078,12 +1017,16 @@ Variable* Scope::DeclareVariableName(const AstRawString* name,
Variable* var = DeclareLocal(name, mode, kind, was_added); Variable* var = DeclareLocal(name, mode, kind, was_added);
if (!*was_added) { if (!*was_added) {
if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) { if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) {
// Duplicate functions are allowed in the sloppy mode, but if this is not if (!var->is_sloppy_block_function() ||
// a function declaration, it's an error. This is an error PreParser kind != SLOPPY_BLOCK_FUNCTION_VARIABLE) {
// Duplicate functions are allowed in the sloppy mode, but if this is
// not a function declaration, it's an error. This is an error PreParser
// hasn't previously detected. // hasn't previously detected.
return nullptr; return nullptr;
} }
if (mode == VariableMode::kVar) var->set_maybe_assigned(); // Sloppy block function redefinition.
}
var->set_maybe_assigned();
} }
var->set_is_used(); var->set_is_used();
return var; return var;
...@@ -1428,7 +1371,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1428,7 +1371,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
locals_.Clear(); locals_.Clear();
inner_scope_ = nullptr; inner_scope_ = nullptr;
unresolved_list_.Clear(); unresolved_list_.Clear();
sloppy_block_function_map_ = nullptr; sloppy_block_functions_.Clear();
rare_data_ = nullptr; rare_data_ = nullptr;
has_rest_ = false; has_rest_ = false;
......
...@@ -43,37 +43,6 @@ class VariableMap: public ZoneHashMap { ...@@ -43,37 +43,6 @@ class VariableMap: public ZoneHashMap {
void Add(Zone* zone, Variable* var); void Add(Zone* zone, Variable* var);
}; };
// Sloppy block-scoped function declarations to var-bind
class SloppyBlockFunctionMap : public ZoneHashMap {
public:
class Delegate : public ZoneObject {
public:
Delegate(Scope* scope, SloppyBlockFunctionStatement* statement, int index)
: scope_(scope), statement_(statement), next_(nullptr), index_(index) {}
void set_statement(Statement* statement);
void set_next(Delegate* next) { next_ = next; }
Delegate* next() const { return next_; }
Scope* scope() const { return scope_; }
int index() const { return index_; }
int position() const { return statement_->position(); }
private:
Scope* scope_;
SloppyBlockFunctionStatement* statement_;
Delegate* next_;
int index_;
};
explicit SloppyBlockFunctionMap(Zone* zone);
void Declare(Zone* zone, const AstRawString* name, Scope* scope,
SloppyBlockFunctionStatement* statement);
private:
int count_;
};
class Scope; class Scope;
template <> template <>
...@@ -940,17 +909,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -940,17 +909,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
void AddLocal(Variable* var); void AddLocal(Variable* var);
void DeclareSloppyBlockFunction( void DeclareSloppyBlockFunction(
const AstRawString* name, Scope* scope, SloppyBlockFunctionStatement* sloppy_block_function);
SloppyBlockFunctionStatement* statement = nullptr);
// Go through sloppy_block_function_map_ and hoist those (into this scope) // Go through sloppy_block_functions_ and hoist those (into this scope)
// which should be hoisted. // which should be hoisted.
void HoistSloppyBlockFunctions(AstNodeFactory* factory); void HoistSloppyBlockFunctions(AstNodeFactory* factory);
SloppyBlockFunctionMap* sloppy_block_function_map() {
return sloppy_block_function_map_;
}
// Compute top scope and allocate variables. For lazy compilation the top // Compute top scope and allocate variables. For lazy compilation the top
// scope only contains the single lazily compiled function, so this // scope only contains the single lazily compiled function, so this
// doesn't re-allocate variables repeatedly. // doesn't re-allocate variables repeatedly.
...@@ -1069,7 +1033,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -1069,7 +1033,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// Parameter list in source order. // Parameter list in source order.
ZonePtrList<Variable> params_; ZonePtrList<Variable> params_;
// Map of function names to lists of functions defined in sloppy blocks // Map of function names to lists of functions defined in sloppy blocks
SloppyBlockFunctionMap* sloppy_block_function_map_; base::ThreadedList<SloppyBlockFunctionStatement> sloppy_block_functions_;
// Convenience variable. // Convenience variable.
Variable* receiver_; Variable* receiver_;
// Function variable, if any; function scopes only. // Function variable, if any; function scopes only.
......
...@@ -137,6 +137,9 @@ class Variable final : public ZoneObject { ...@@ -137,6 +137,9 @@ class Variable final : public ZoneObject {
} }
bool is_parameter() const { return kind() == PARAMETER_VARIABLE; } bool is_parameter() const { return kind() == PARAMETER_VARIABLE; }
bool is_sloppy_block_function() {
return kind() == SLOPPY_BLOCK_FUNCTION_VARIABLE;
}
Variable* local_if_not_shadowed() const { Variable* local_if_not_shadowed() const {
DCHECK(mode() == VariableMode::kDynamicLocal && DCHECK(mode() == VariableMode::kDynamicLocal &&
...@@ -207,7 +210,7 @@ class Variable final : public ZoneObject { ...@@ -207,7 +210,7 @@ class Variable final : public ZoneObject {
class VariableModeField : public BitField16<VariableMode, 0, 3> {}; class VariableModeField : public BitField16<VariableMode, 0, 3> {};
class VariableKindField class VariableKindField
: public BitField16<VariableKind, VariableModeField::kNext, 2> {}; : public BitField16<VariableKind, VariableModeField::kNext, 3> {};
class LocationField class LocationField
: public BitField16<VariableLocation, VariableKindField::kNext, 3> {}; : public BitField16<VariableLocation, VariableKindField::kNext, 3> {};
class ForceContextAllocationField class ForceContextAllocationField
......
...@@ -1099,6 +1099,7 @@ enum VariableKind : uint8_t { ...@@ -1099,6 +1099,7 @@ enum VariableKind : uint8_t {
NORMAL_VARIABLE, NORMAL_VARIABLE,
PARAMETER_VARIABLE, PARAMETER_VARIABLE,
THIS_VARIABLE, THIS_VARIABLE,
SLOPPY_BLOCK_FUNCTION_VARIABLE,
SLOPPY_FUNCTION_NAME_VARIABLE SLOPPY_FUNCTION_NAME_VARIABLE
}; };
......
...@@ -3648,10 +3648,10 @@ ParserBase<Impl>::ParseHoistableDeclaration( ...@@ -3648,10 +3648,10 @@ ParserBase<Impl>::ParseHoistableDeclaration(
FuncNameInferrerState fni_state(&fni_); FuncNameInferrerState fni_state(&fni_);
impl()->PushEnclosingName(name); impl()->PushEnclosingName(name);
FunctionKind kind = FunctionKindFor(flags); FunctionKind function_kind = FunctionKindFor(flags);
FunctionLiteralT function = impl()->ParseFunctionLiteral( FunctionLiteralT function = impl()->ParseFunctionLiteral(
name, scanner()->location(), name_validity, kind, pos, name, scanner()->location(), name_validity, function_kind, pos,
FunctionLiteral::kDeclaration, language_mode(), nullptr); FunctionLiteral::kDeclaration, language_mode(), nullptr);
// In ES6, a function behaves as a lexical binding, except in // In ES6, a function behaves as a lexical binding, except in
...@@ -3662,16 +3662,17 @@ ParserBase<Impl>::ParseHoistableDeclaration( ...@@ -3662,16 +3662,17 @@ ParserBase<Impl>::ParseHoistableDeclaration(
: VariableMode::kVar; : VariableMode::kVar;
// Async functions don't undergo sloppy mode block scoped hoisting, and don't // Async functions don't undergo sloppy mode block scoped hoisting, and don't
// allow duplicates in a block. Both are represented by the // allow duplicates in a block. Both are represented by the
// sloppy_block_function_map. Don't add them to the map for async functions. // sloppy_block_functions_. Don't add them to the map for async functions.
// Generators are also supposed to be prohibited; currently doing this behind // Generators are also supposed to be prohibited; currently doing this behind
// a flag and UseCounting violations to assess web compatibility. // a flag and UseCounting violations to assess web compatibility.
bool is_sloppy_block_function = is_sloppy(language_mode()) && VariableKind kind = is_sloppy(language_mode()) &&
!scope()->is_declaration_scope() && !scope()->is_declaration_scope() &&
flags == ParseFunctionFlag::kIsNormal; flags == ParseFunctionFlag::kIsNormal
? SLOPPY_BLOCK_FUNCTION_VARIABLE
: NORMAL_VARIABLE;
return impl()->DeclareFunction(variable_name, function, mode, pos, return impl()->DeclareFunction(variable_name, function, mode, kind, pos,
end_position(), is_sloppy_block_function, end_position(), names);
names);
} }
template <typename Impl> template <typename Impl>
......
...@@ -1438,20 +1438,20 @@ Statement* Parser::BuildInitializationBlock( ...@@ -1438,20 +1438,20 @@ Statement* Parser::BuildInitializationBlock(
Statement* Parser::DeclareFunction(const AstRawString* variable_name, Statement* Parser::DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, VariableMode mode, FunctionLiteral* function, VariableMode mode,
int beg_pos, int end_pos, VariableKind kind, int beg_pos, int end_pos,
bool is_sloppy_block_function,
ZonePtrList<const AstRawString>* names) { ZonePtrList<const AstRawString>* names) {
Declaration* declaration = factory()->NewFunctionDeclaration( Declaration* declaration =
function, is_sloppy_block_function, beg_pos); factory()->NewFunctionDeclaration(function, beg_pos);
bool was_added; bool was_added;
Declare(declaration, variable_name, NORMAL_VARIABLE, mode, Declare(declaration, variable_name, kind, mode, kCreatedInitialized, scope(),
kCreatedInitialized, scope(), &was_added, beg_pos); &was_added, beg_pos);
if (names) names->Add(variable_name, zone()); if (names) names->Add(variable_name, zone());
if (is_sloppy_block_function) { if (kind == SLOPPY_BLOCK_FUNCTION_VARIABLE) {
Token::Value init = loop_nesting_depth() > 0 ? Token::ASSIGN : Token::INIT;
SloppyBlockFunctionStatement* statement = SloppyBlockFunctionStatement* statement =
factory()->NewSloppyBlockFunctionStatement(end_pos); factory()->NewSloppyBlockFunctionStatement(end_pos, declaration->var(),
GetDeclarationScope()->DeclareSloppyBlockFunction(variable_name, scope(), init);
statement); GetDeclarationScope()->DeclareSloppyBlockFunction(statement);
return statement; return statement;
} }
return factory()->EmptyStatement(); return factory()->EmptyStatement();
......
...@@ -341,8 +341,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -341,8 +341,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Statement* DeclareFunction(const AstRawString* variable_name, Statement* DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, VariableMode mode, FunctionLiteral* function, VariableMode mode,
int beg_pos, int end_pos, VariableKind kind, int beg_pos, int end_pos,
bool is_sloppy_block_function,
ZonePtrList<const AstRawString>* names); ZonePtrList<const AstRawString>* names);
Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name); Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name);
FunctionLiteral* CreateInitializerFunction( FunctionLiteral* CreateInitializerFunction(
......
...@@ -1101,16 +1101,14 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1101,16 +1101,14 @@ class PreParser : public ParserBase<PreParser> {
// Don't bother actually binding the proxy. // Don't bother actually binding the proxy.
} }
void DeclareVariableName(const AstRawString* name, VariableMode mode, Variable* DeclareVariableName(const AstRawString* name, VariableMode mode,
Scope* scope, bool* was_added, Scope* scope, bool* was_added,
int position = kNoSourcePosition, int position = kNoSourcePosition,
VariableKind kind = NORMAL_VARIABLE) { VariableKind kind = NORMAL_VARIABLE) {
Variable* var = scope->DeclareVariableName(name, mode, was_added, kind); Variable* var = scope->DeclareVariableName(name, mode, was_added, kind);
if (var == nullptr) { if (var == nullptr) {
ReportUnidentifiableError(); ReportUnidentifiableError();
return; } else if (var->scope() != scope) {
}
if (var->scope() != scope) {
DCHECK_NE(kNoSourcePosition, position); DCHECK_NE(kNoSourcePosition, position);
DCHECK_EQ(VariableMode::kVar, mode); DCHECK_EQ(VariableMode::kVar, mode);
Declaration* nested_declaration = Declaration* nested_declaration =
...@@ -1119,6 +1117,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1119,6 +1117,7 @@ class PreParser : public ParserBase<PreParser> {
nested_declaration->set_var(var); nested_declaration->set_var(var);
var->scope()->declarations()->Add(nested_declaration); var->scope()->declarations()->Add(nested_declaration);
} }
return var;
} }
V8_INLINE PreParserBlock RewriteCatchPattern(CatchInfo* catch_info) { V8_INLINE PreParserBlock RewriteCatchPattern(CatchInfo* catch_info) {
...@@ -1183,22 +1182,22 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1183,22 +1182,22 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
V8_INLINE PreParserStatement V8_INLINE PreParserStatement DeclareFunction(
DeclareFunction(const PreParserIdentifier& variable_name, const PreParserIdentifier& variable_name,
const PreParserExpression& function, VariableMode mode, const PreParserExpression& function, VariableMode mode, VariableKind kind,
int beg_pos, int end_pos, bool is_sloppy_block_function, int beg_pos, int end_pos, ZonePtrList<const AstRawString>* names) {
ZonePtrList<const AstRawString>* names) {
DCHECK_NULL(names); DCHECK_NULL(names);
if (variable_name.string_ != nullptr) { if (variable_name.string_ != nullptr) {
bool was_added; bool was_added;
if (is_strict(language_mode())) { Variable* var = DeclareVariableName(variable_name.string_, mode, scope(),
DeclareVariableName(variable_name.string_, mode, scope(), &was_added); &was_added, beg_pos, kind);
} else { if (kind == SLOPPY_BLOCK_FUNCTION_VARIABLE) {
scope()->DeclareVariableName(variable_name.string_, mode, &was_added); Token::Value init =
} loop_nesting_depth() > 0 ? Token::ASSIGN : Token::INIT;
if (is_sloppy_block_function) { SloppyBlockFunctionStatement* statement =
GetDeclarationScope()->DeclareSloppyBlockFunction(variable_name.string_, factory()->ast_node_factory()->NewSloppyBlockFunctionStatement(
scope()); end_pos, var, init);
GetDeclarationScope()->DeclareSloppyBlockFunction(statement);
} }
} }
return Statement::Default(); return Statement::Default();
......
...@@ -2,11 +2,16 @@ ...@@ -2,11 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
assertThrows(`
{ {
function a() {} function a() {}
} }
{ {
// Duplicate lexical declarations are only allowed if they are both sloppy
// block functions (see bug 4693). In this case the sloppy block function
// conflicts with the lexical variable declaration, causing a syntax error.
let a; let a;
function a() {}; function a() {};
} }
`, SyntaxError)
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