[parser] Pessimistically assume top-level variables will be assigned.

We have to pessimistically assume that top-level variables will be assigned.
This is because there may be lazily parsed top-level functions, which, for
efficiency, we preparse without variable tracking.

R=adamk@chromium.org, marja@chromium.org
CC=jarin@chromium.org
BUG=v8:5636

Review-Url: https://codereview.chromium.org/2634123002
Cr-Commit-Position: refs/heads/master@{#42398}
This commit is contained in:
neis 2017-01-17 02:40:00 -08:00 committed by Commit bot
parent 68c994795e
commit 248d1b3de9
2 changed files with 68 additions and 0 deletions

View File

@ -224,6 +224,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
} else {
DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(proxy->var());
if (var_init_scope->is_script_scope() ||
var_init_scope->is_module_scope()) {
// We have to pessimistically assume that top-level variables will be
// assigned. This is because there may be lazily parsed top-level
// functions, which, for efficiency, we preparse without variable
// tracking.
proxy->set_is_assigned();
}
}
// Add break location for destructured sub-pattern.
int pos = IsSubPattern() ? pattern->position() : value->position();

View File

@ -3515,6 +3515,66 @@ TEST(MaybeAssignedParameters) {
}
}
TEST(MaybeAssignedTopLevel) {
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
LocalContext env;
i::Factory* factory = isolate->factory();
const char* prefixes[] = {
"let foo; ", "let foo = 0; ",
"let [foo] = [1]; ", "let {foo} = {foo: 2}; ",
"let {foo=3} = {}; ",
};
const char* sources[] = {
"function bar() {foo = 42}; ext(bar); ext(foo)",
"ext(function() {foo++}); ext(foo)",
"bar = () => --foo; ext(bar); ext(foo)",
"function* bar() {eval(ext)}; ext(bar); ext(foo)",
};
for (unsigned i = 0; i < arraysize(prefixes); ++i) {
const char* prefix = prefixes[i];
for (unsigned j = 0; j < arraysize(sources); ++j) {
const char* source = sources[j];
i::ScopedVector<char> program(Utf8LengthHelper(prefix) +
Utf8LengthHelper(source) + 1);
i::SNPrintF(program, "%s%s", prefix, source);
i::Zone zone(isolate->allocator(), ZONE_NAME);
i::Handle<i::String> string =
factory->InternalizeUtf8String(program.start());
string->PrintOn(stdout);
printf("\n");
i::Handle<i::Script> script = factory->NewScript(string);
for (unsigned allow_lazy = 0; allow_lazy < 2; ++allow_lazy) {
for (unsigned module = 0; module < 2; ++module) {
std::unique_ptr<i::ParseInfo> info;
info = std::unique_ptr<i::ParseInfo>(new i::ParseInfo(&zone, script));
info->set_module(module);
info->set_allow_lazy_parsing(allow_lazy);
CHECK(i::parsing::ParseProgram(info.get()));
CHECK(i::Compiler::Analyze(info.get()));
CHECK_NOT_NULL(info->literal());
i::Scope* scope = info->literal()->scope();
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
CHECK_NULL(scope->sibling());
CHECK(module ? scope->is_module_scope() : scope->is_script_scope());
const i::AstRawString* var_name =
info->ast_value_factory()->GetOneByteString("foo");
i::Variable* var = scope->Lookup(var_name);
CHECK(var->is_used());
CHECK(var->maybe_assigned() == i::kMaybeAssigned);
}
}
}
}
}
namespace {
i::Scope* DeserializeFunctionScope(i::Isolate* isolate, i::Zone* zone,