From 248d1b3de9872c21df3a92dbaff5c81e2026e0dc Mon Sep 17 00:00:00 2001 From: neis Date: Tue, 17 Jan 2017 02:40:00 -0800 Subject: [PATCH] [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} --- src/parsing/pattern-rewriter.cc | 8 +++++ test/cctest/test-parsing.cc | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc index edd283e9d6..9eb3f0665b 100644 --- a/src/parsing/pattern-rewriter.cc +++ b/src/parsing/pattern-rewriter.cc @@ -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(); diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index d668dd377b..06dcc3a1c9 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -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 program(Utf8LengthHelper(prefix) + + Utf8LengthHelper(source) + 1); + i::SNPrintF(program, "%s%s", prefix, source); + i::Zone zone(isolate->allocator(), ZONE_NAME); + + i::Handle string = + factory->InternalizeUtf8String(program.start()); + string->PrintOn(stdout); + printf("\n"); + i::Handle script = factory->NewScript(string); + + for (unsigned allow_lazy = 0; allow_lazy < 2; ++allow_lazy) { + for (unsigned module = 0; module < 2; ++module) { + std::unique_ptr info; + info = std::unique_ptr(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,