Commit a450d3ae authored by neis's avatar neis Committed by Commit bot

[parsing] Fix maybe-assigned for top-level class declarations.

Move the logic into Scope::DeclareVariable to be more robust.

BUG=v8:5636

Review-Url: https://codereview.chromium.org/2685293003
Cr-Commit-Position: refs/heads/master@{#43098}
parent fc1af41d
...@@ -1009,6 +1009,17 @@ Variable* Scope::DeclareVariable( ...@@ -1009,6 +1009,17 @@ Variable* Scope::DeclareVariable(
const AstRawString* name = proxy->raw_name(); const AstRawString* name = proxy->raw_name();
bool is_function_declaration = declaration->IsFunctionDeclaration(); bool is_function_declaration = declaration->IsFunctionDeclaration();
// Pessimistically assume that top-level variables will be assigned.
//
// Top-level variables in a script can be accessed by other scripts or even
// become global properties. While this does not apply to top-level variables
// in a module (assuming they are not exported), we must still mark these as
// assigned because they might be accessed by a lazily parsed top-level
// function, which, for efficiency, we preparse without variable tracking.
if (is_script_scope() || is_module_scope()) {
if (mode != CONST) proxy->set_is_assigned();
}
Variable* var = nullptr; Variable* var = nullptr;
if (is_eval_scope() && is_sloppy(language_mode()) && mode == VAR) { if (is_eval_scope() && is_sloppy(language_mode()) && mode == VAR) {
// In a var binding in a sloppy direct eval, pollute the enclosing scope // In a var binding in a sloppy direct eval, pollute the enclosing scope
...@@ -1152,6 +1163,7 @@ Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name, ...@@ -1152,6 +1163,7 @@ Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
VariableKind kind) { VariableKind kind) {
DCHECK(is_script_scope()); DCHECK(is_script_scope());
return variables_.Declare(zone(), this, name, DYNAMIC_GLOBAL, kind); return variables_.Declare(zone(), this, name, DYNAMIC_GLOBAL, kind);
// TODO(neis): Mark variable as maybe-assigned?
} }
......
...@@ -1487,8 +1487,6 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name, ...@@ -1487,8 +1487,6 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
VariableProxy* proxy = VariableProxy* proxy =
factory()->NewVariableProxy(variable_name, NORMAL_VARIABLE); factory()->NewVariableProxy(variable_name, NORMAL_VARIABLE);
MarkTopLevelVariableAsAssigned(scope(), proxy);
Declaration* declaration = Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, function, scope(), pos); factory()->NewFunctionDeclaration(proxy, function, scope(), pos);
Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized, Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized,
......
...@@ -824,20 +824,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -824,20 +824,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
} }
} }
// Pessimistically assume that top-level variables will be assigned.
//
// Top-level variables in a script can be accessed by other scripts or even
// become global properties. While this does not apply to top-level variables
// in a module (assuming they are not exported), we must still mark these as
// assigned because they might be accessed by a lazily parsed top-level
// function, which, for efficiency, we preparse without variable tracking.
V8_INLINE static void MarkTopLevelVariableAsAssigned(Scope* scope,
VariableProxy* proxy) {
if (scope->is_script_scope() || scope->is_module_scope()) {
proxy->set_is_assigned();
}
}
// Returns true if we have a binary expression between two numeric // Returns true if we have a binary expression between two numeric
// literals. In that case, *x will be changed to an expression which is the // literals. In that case, *x will be changed to an expression which is the
// computed value. // computed value.
......
...@@ -171,12 +171,10 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -171,12 +171,10 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
names_->Add(name, zone()); names_->Add(name, zone());
} }
Scope* var_init_scope = descriptor_->scope;
MarkTopLevelVariableAsAssigned(var_init_scope, proxy);
// If there's no initializer, we're done. // If there's no initializer, we're done.
if (value == nullptr) return; if (value == nullptr) return;
Scope* var_init_scope = descriptor_->scope;
MarkLoopVariableAsAssigned(var_init_scope, proxy->var()); MarkLoopVariableAsAssigned(var_init_scope, proxy->var());
// A declaration of the form: // A declaration of the form:
......
...@@ -3853,12 +3853,21 @@ TEST(MaybeAssignedTopLevel) { ...@@ -3853,12 +3853,21 @@ TEST(MaybeAssignedTopLevel) {
i::Factory* factory = isolate->factory(); i::Factory* factory = isolate->factory();
const char* prefixes[] = { const char* prefixes[] = {
"let foo; ", "let foo = 0; ", "let foo; ",
"let [foo] = [1]; ", "let {foo} = {foo: 2}; ", "let foo = 0; ",
"let {foo=3} = {}; ", "function foo() {}; ", "let [foo] = [1]; ",
"var foo; ", "var foo = 0; ", "let {foo} = {foo: 2}; ",
"var [foo] = [1]; ", "var {foo} = {foo: 2}; ", "let {foo=3} = {}; ",
"var {foo=3} = {}; ", "function* foo() {}; ", "var foo; ",
"var foo = 0; ",
"var [foo] = [1]; ",
"var {foo} = {foo: 2}; ",
"var {foo=3} = {}; ",
"function foo() {}; ",
"function* foo() {}; ",
"async function foo() {}; ",
"class foo {}; ",
"class foo extends null {}; ",
}; };
const char* sources[] = { const char* sources[] = {
"function bar() {foo = 42}; ext(bar); ext(foo)", "function bar() {foo = 42}; ext(bar); ext(foo)",
......
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