Commit 5f9c89af authored by hablich's avatar hablich Committed by Commit bot

Reland of [parsing] Fix maybe-assigned for loop variables. (patchset #1 id:1...

Reland of [parsing] Fix maybe-assigned for loop variables. (patchset #1 id:1 of https://codereview.chromium.org/2679263002/ )

Reason for revert:
False alarm, bot hiccup

Original issue's description:
> Revert of [parsing] Fix maybe-assigned for loop variables. (patchset #3 id:40001 of https://codereview.chromium.org/2673403003/ )
>
> Reason for revert:
> Speculative revert because of https://codereview.chromium.org/2679163002/.
>
> Original issue's description:
> > [parsing] Fix maybe-assigned for loop variables.
> >
> > Due to hoisting, the value of a 'var'-declared variable may actually change even
> > if the code contains only the "initial" assignment, namely when that assignment
> > occurs inside a loop.  For example:
> >
> >   let i = 10;
> >   do { var x = i } while (i--):
> >
> > As a simple and very conservative approximation of this, we explicitly mark
> > as maybe-assigned any non-lexical variable whose "declaration" does not
> > syntactically occur in the function scope.  (In the example above, it
> > occurs in a block scope.)
> >
> > BUG=v8:5636
> >
> > Review-Url: https://codereview.chromium.org/2673403003
> > Cr-Commit-Position: refs/heads/master@{#42989}
> > Committed: https://chromium.googlesource.com/v8/v8/+/a33fcd663b28b8846e12b97c30d6e7d837767f86
>
> TBR=marja@chromium.org,adamk@chromium.org,neis@chromium.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=v8:5636
>
> Review-Url: https://codereview.chromium.org/2679263002
> Cr-Commit-Position: refs/heads/master@{#43010}
> Committed: https://chromium.googlesource.com/v8/v8/+/f3ae5ccf57690d8c2d87c4fe1d10b103ad6a4ab3

TBR=marja@chromium.org,adamk@chromium.org,neis@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:5636

Review-Url: https://codereview.chromium.org/2686663002
Cr-Commit-Position: refs/heads/master@{#43013}
parent 96e4f614
...@@ -181,6 +181,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -181,6 +181,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
bool* sloppy_mode_block_scope_function_redefinition, bool* sloppy_mode_block_scope_function_redefinition,
bool* ok); bool* ok);
// 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);
// Declarations list. // Declarations list.
......
...@@ -1347,6 +1347,24 @@ class ParserBase { ...@@ -1347,6 +1347,24 @@ class ParserBase {
return expression->IsObjectLiteral() || expression->IsArrayLiteral(); return expression->IsObjectLiteral() || expression->IsArrayLiteral();
} }
// Due to hoisting, the value of a 'var'-declared variable may actually change
// even if the code contains only the "initial" assignment, namely when that
// assignment occurs inside a loop. For example:
//
// let i = 10;
// do { var x = i } while (i--):
//
// As a simple and very conservative approximation of this, we explicitly mark
// as maybe-assigned any non-lexical variable whose initializing "declaration"
// does not syntactically occur in the function scope. (In the example above,
// it occurs in a block scope.)
//
// Note that non-lexical variables include temporaries, which may also get
// assigned inside a loop due to the various rewritings that the parser
// performs.
//
static void MarkLoopVariableAsAssigned(Scope* scope, Variable* var);
// Keep track of eval() calls since they disable all local variable // Keep track of eval() calls since they disable all local variable
// optimizations. This checks if expression is an eval call, and if yes, // optimizations. This checks if expression is an eval call, and if yes,
// forwards the information to scope. // forwards the information to scope.
...@@ -5698,8 +5716,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( ...@@ -5698,8 +5716,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop(
return loop; return loop;
} }
#undef CHECK_OK template <typename Impl>
#undef CHECK_OK_CUSTOM void ParserBase<Impl>::MarkLoopVariableAsAssigned(Scope* scope, Variable* var) {
if (!IsLexicalVariableMode(var->mode()) && !scope->is_function_scope()) {
var->set_maybe_assigned();
}
}
template <typename Impl> template <typename Impl>
void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto( void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
...@@ -5751,6 +5773,8 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName( ...@@ -5751,6 +5773,8 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
} }
} }
#undef CHECK_OK
#undef CHECK_OK_CUSTOM
#undef CHECK_OK_VOID #undef CHECK_OK_VOID
} // namespace internal } // namespace internal
......
...@@ -177,6 +177,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -177,6 +177,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// If there's no initializer, we're done. // If there's no initializer, we're done.
if (value == nullptr) return; if (value == nullptr) return;
MarkLoopVariableAsAssigned(var_init_scope, proxy->var());
// A declaration of the form: // A declaration of the form:
// //
// var v = x; // var v = x;
......
...@@ -310,8 +310,14 @@ void PreParser::DeclareAndInitializeVariables( ...@@ -310,8 +310,14 @@ void PreParser::DeclareAndInitializeVariables(
DCHECK(track_unresolved_variables_); DCHECK(track_unresolved_variables_);
for (auto variable : *(declaration->pattern.variables_)) { for (auto variable : *(declaration->pattern.variables_)) {
declaration_descriptor->scope->RemoveUnresolved(variable); declaration_descriptor->scope->RemoveUnresolved(variable);
scope()->DeclareVariableName(variable->raw_name(), Variable* var = scope()->DeclareVariableName(
declaration_descriptor->mode); variable->raw_name(), declaration_descriptor->mode);
if (FLAG_preparser_scope_analysis) {
MarkLoopVariableAsAssigned(declaration_descriptor->scope, var);
// This is only necessary if there is an initializer, but we don't have
// that information here. Consequently, the preparser sometimes says
// maybe-assigned where the parser (correctly) says never-assigned.
}
if (names) { if (names) {
names->Add(variable->raw_name(), zone()); names->Add(variable->raw_name(), zone());
} }
......
...@@ -30,268 +30,274 @@ TEST(PreParserScopeAnalysis) { ...@@ -30,268 +30,274 @@ TEST(PreParserScopeAnalysis) {
const char* eager_inner = "(function inner(%s) { %s })()"; const char* eager_inner = "(function inner(%s) { %s })()";
struct { struct {
bool precise_maybe_assigned;
const char* params; const char* params;
const char* source; const char* source;
} inners[] = { } inners[] = {
// Simple cases // Simple cases
{"", "var1;"}, {1, "", "var1;"},
{"", "var1 = 5;"}, {1, "", "var1 = 5;"},
{"", "if (true) {}"}, {1, "", "if (true) {}"},
{"", "function f1() {}"}, {1, "", "function f1() {}"},
// Var declarations and assignments. // Var declarations and assignments.
{"", "var var1;"}, {1, "", "var var1;"},
{"", "var var1; var1 = 5;"}, {1, "", "var var1; var1 = 5;"},
{"", "if (true) { var var1; }"}, {0, "", "if (true) { var var1; }"},
{"", "if (true) { var var1; var1 = 5; }"}, {1, "", "if (true) { var var1; var1 = 5; }"},
{"", "var var1; function f() { var1; }"}, {1, "", "var var1; function f() { var1; }"},
{"", "var var1; var1 = 5; function f() { var1; }"}, {1, "", "var var1; var1 = 5; function f() { var1; }"},
{"", "var var1; function f() { var1 = 5; }"}, {1, "", "var var1; function f() { var1 = 5; }"},
// Let declarations and assignments. // Let declarations and assignments.
{"", "let var1;"}, {1, "", "let var1;"},
{"", "let var1; var1 = 5;"}, {1, "", "let var1; var1 = 5;"},
{"", "if (true) { let var1; }"}, {1, "", "if (true) { let var1; }"},
{"", "if (true) { let var1; var1 = 5; }"}, {1, "", "if (true) { let var1; var1 = 5; }"},
{"", "let var1; function f() { var1; }"}, {1, "", "let var1; function f() { var1; }"},
{"", "let var1; var1 = 5; function f() { var1; }"}, {1, "", "let var1; var1 = 5; function f() { var1; }"},
{"", "let var1; function f() { var1 = 5; }"}, {1, "", "let var1; function f() { var1 = 5; }"},
// Const declarations. // Const declarations.
{"", "const var1 = 5;"}, {1, "", "const var1 = 5;"},
{"", "if (true) { const var1 = 5; }"}, {1, "", "if (true) { const var1 = 5; }"},
{"", "const var1 = 5; function f() { var1; }"}, {1, "", "const var1 = 5; function f() { var1; }"},
// Redeclarations. // Redeclarations.
{"", "var var1; var var1;"}, {1, "", "var var1; var var1;"},
{"", "var var1; var var1; var1 = 5;"}, {1, "", "var var1; var var1; var1 = 5;"},
{"", "var var1; if (true) { var var1; }"}, {1, "", "var var1; if (true) { var var1; }"},
{"", "if (true) { var var1; var var1; }"}, {1, "", "if (true) { var var1; var var1; }"},
{"", "var var1; if (true) { var var1; var1 = 5; }"}, {1, "", "var var1; if (true) { var var1; var1 = 5; }"},
{"", "if (true) { var var1; var var1; var1 = 5; }"}, {1, "", "if (true) { var var1; var var1; var1 = 5; }"},
{"", "var var1; var var1; function f() { var1; }"}, {1, "", "var var1; var var1; function f() { var1; }"},
{"", "var var1; var var1; function f() { var1 = 5; }"}, {1, "", "var var1; var var1; function f() { var1 = 5; }"},
// Shadowing declarations. // Shadowing declarations.
{"", "var var1; if (true) { var var1; }"}, {1, "", "var var1; if (true) { var var1; }"},
{"", "var var1; if (true) { let var1; }"}, {1, "", "var var1; if (true) { let var1; }"},
{"", "let var1; if (true) { let var1; }"}, {1, "", "let var1; if (true) { let var1; }"},
{"", "var var1; if (true) { const var1 = 0; }"}, {1, "", "var var1; if (true) { const var1 = 0; }"},
{"", "const var1 = 0; if (true) { const var1 = 0; }"}, {1, "", "const var1 = 0; if (true) { const var1 = 0; }"},
// Arguments and this. // Arguments and this.
{"", "arguments;"}, {1, "", "arguments;"},
{"", "arguments = 5;"}, {1, "", "arguments = 5;"},
{"", "if (true) { arguments; }"}, {1, "", "if (true) { arguments; }"},
{"", "if (true) { arguments = 5; }"}, {1, "", "if (true) { arguments = 5; }"},
{"", "function f() { arguments; }"}, {1, "", "function f() { arguments; }"},
{"", "function f() { arguments = 5; }"}, {1, "", "function f() { arguments = 5; }"},
{"", "this;"}, {1, "", "this;"},
{"", "if (true) { this; }"}, {1, "", "if (true) { this; }"},
{"", "function f() { this; }"}, {1, "", "function f() { this; }"},
// Variable called "arguments" // Variable called "arguments"
{"", "var arguments;"}, {1, "", "var arguments;"},
{"", "var arguments; arguments = 5;"}, {1, "", "var arguments; arguments = 5;"},
{"", "if (true) { var arguments; }"}, {0, "", "if (true) { var arguments; }"},
{"", "if (true) { var arguments; arguments = 5; }"}, {1, "", "if (true) { var arguments; arguments = 5; }"},
{"", "var arguments; function f() { arguments; }"}, {1, "", "var arguments; function f() { arguments; }"},
{"", "var arguments; arguments = 5; function f() { arguments; }"}, {1, "", "var arguments; arguments = 5; function f() { arguments; }"},
{"", "var arguments; function f() { arguments = 5; }"}, {1, "", "var arguments; function f() { arguments = 5; }"},
{"", "let arguments;"}, {1, "", "let arguments;"},
{"", "let arguments; arguments = 5;"}, {1, "", "let arguments; arguments = 5;"},
{"", "if (true) { let arguments; }"}, {1, "", "if (true) { let arguments; }"},
{"", "if (true) { let arguments; arguments = 5; }"}, {1, "", "if (true) { let arguments; arguments = 5; }"},
{"", "let arguments; function f() { arguments; }"}, {1, "", "let arguments; function f() { arguments; }"},
{"", "let arguments; arguments = 5; function f() { arguments; }"}, {1, "", "let arguments; arguments = 5; function f() { arguments; }"},
{"", "let arguments; function f() { arguments = 5; }"}, {1, "", "let arguments; function f() { arguments = 5; }"},
{"", "const arguments = 5;"}, {1, "", "const arguments = 5;"},
{"", "if (true) { const arguments = 5; }"}, {1, "", "if (true) { const arguments = 5; }"},
{"", "const arguments = 5; function f() { arguments; }"}, {1, "", "const arguments = 5; function f() { arguments; }"},
// Destructuring declarations. // Destructuring declarations.
{"", "var [var1, var2] = [1, 2];"}, {1, "", "var [var1, var2] = [1, 2];"},
{"", "var [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"}, {1, "", "var [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "var [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"}, {1, "", "var [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "var [var1, ...var2] = [1, 2, 3];"}, {1, "", "var [var1, ...var2] = [1, 2, 3];"},
{"", "var {var1: var2, var3: var4} = {var1: 1, var3: 2};"}, {1, "", "var {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"", {1, "",
"var {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, "var {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "var {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, {1, "",
"var {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
{"", "let [var1, var2] = [1, 2];"}, {1, "", "let [var1, var2] = [1, 2];"},
{"", "let [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"}, {1, "", "let [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "let [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"}, {1, "", "let [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "let [var1, ...var2] = [1, 2, 3];"}, {1, "", "let [var1, ...var2] = [1, 2, 3];"},
{"", "let {var1: var2, var3: var4} = {var1: 1, var3: 2};"}, {1, "", "let {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"", {1, "",
"let {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, "let {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "let {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, {1, "",
"let {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
{"", "const [var1, var2] = [1, 2];"}, {1, "", "const [var1, var2] = [1, 2];"},
{"", "const [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"}, {1, "", "const [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "const [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"}, {1, "", "const [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "const [var1, ...var2] = [1, 2, 3];"}, {1, "", "const [var1, ...var2] = [1, 2, 3];"},
{"", "const {var1: var2, var3: var4} = {var1: 1, var3: 2};"}, {1, "", "const {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"", {1, "",
"const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, "const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, {1, "",
"const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
// Referencing the function variable. // Referencing the function variable.
{"", "inner;"}, {1, "", "inner;"},
{"", "function f1() { f1; }"}, {1, "", "function f1() { f1; }"},
{"", "function f1() { inner; }"}, {1, "", "function f1() { inner; }"},
{"", "function f1() { function f2() { f1; } }"}, {1, "", "function f1() { function f2() { f1; } }"},
{"", "function arguments() {}"}, {1, "", "function arguments() {}"},
{"", "function f1() {} function f1() {}"}, {1, "", "function f1() {} function f1() {}"},
{"", "var f1; function f1() {}"}, {1, "", "var f1; function f1() {}"},
// Assigning to the function variable. // Assigning to the function variable.
{"", "inner = 3;"}, {1, "", "inner = 3;"},
{"", "function f1() { f1 = 3; }"}, {1, "", "function f1() { f1 = 3; }"},
{"", "function f1() { f1; } f1 = 3;"}, {1, "", "function f1() { f1; } f1 = 3;"},
{"", "function arguments() {} arguments = 8"}, {1, "", "function arguments() {} arguments = 8"},
{"", "function f1() {} f1 = 3; function f1() {}"}, {1, "", "function f1() {} f1 = 3; function f1() {}"},
// Evals. // Evals.
{"", "var var1; eval('');"}, {1, "", "var var1; eval('');"},
{"", "var var1; function f1() { eval(''); }"}, {1, "", "var var1; function f1() { eval(''); }"},
{"", "let var1; eval('');"}, {1, "", "let var1; eval('');"},
{"", "let var1; function f1() { eval(''); }"}, {1, "", "let var1; function f1() { eval(''); }"},
{"", "const var1 = 10; eval('');"}, {1, "", "const var1 = 10; eval('');"},
{"", "const var1 = 10; function f1() { eval(''); }"}, {1, "", "const var1 = 10; function f1() { eval(''); }"},
// Standard for loops. // Standard for loops.
{"", "for (var var1 = 0; var1 < 10; ++var1) { }"}, {1, "", "for (var var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (let var1 = 0; var1 < 10; ++var1) { }"}, {1, "", "for (let var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (const var1 = 0; var1 < 10; ++var1) { }"}, {1, "", "for (const var1 = 0; var1 < 10; ++var1) { }"},
{"", {1, "",
"for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"}, "for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"", {1, "",
"for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"}, "for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"", {1, "",
"for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"}, "for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"", {1, "",
"'use strict'; for (var var1 = 0; var1 < 10; ++var1) { function foo() { " "'use strict'; for (var var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"}, "var1; } }"},
{"", {1, "",
"'use strict'; for (let var1 = 0; var1 < 10; ++var1) { function foo() { " "'use strict'; for (let var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"}, "var1; } }"},
{"", {1, "",
"'use strict'; for (const var1 = 0; var1 < 10; ++var1) { function foo() " "'use strict'; for (const var1 = 0; var1 < 10; ++var1) { function foo() "
"{ var1; } }"}, "{ var1; } }"},
// For of loops // For of loops
{"", "for (var1 of [1, 2]) { }"}, {1, "", "for (var1 of [1, 2]) { }"},
{"", "for (var var1 of [1, 2]) { }"}, {1, "", "for (var var1 of [1, 2]) { }"},
{"", "for (let var1 of [1, 2]) { }"}, {1, "", "for (let var1 of [1, 2]) { }"},
{"", "for (const var1 of [1, 2]) { }"}, {1, "", "for (const var1 of [1, 2]) { }"},
{"", "for (var1 of [1, 2]) { var1; }"}, {1, "", "for (var1 of [1, 2]) { var1; }"},
{"", "for (var var1 of [1, 2]) { var1; }"}, {1, "", "for (var var1 of [1, 2]) { var1; }"},
{"", "for (let var1 of [1, 2]) { var1; }"}, {1, "", "for (let var1 of [1, 2]) { var1; }"},
{"", "for (const var1 of [1, 2]) { var1; }"}, {1, "", "for (const var1 of [1, 2]) { var1; }"},
{"", "for (var1 of [1, 2]) { var1 = 0; }"}, {1, "", "for (var1 of [1, 2]) { var1 = 0; }"},
{"", "for (var var1 of [1, 2]) { var1 = 0; }"}, {1, "", "for (var var1 of [1, 2]) { var1 = 0; }"},
{"", "for (let var1 of [1, 2]) { var1 = 0; }"}, {1, "", "for (let var1 of [1, 2]) { var1 = 0; }"},
{"", "for (const var1 of [1, 2]) { var1 = 0; }"}, {1, "", "for (const var1 of [1, 2]) { var1 = 0; }"},
{"", "for (var1 of [1, 2]) { function foo() { var1; } }"}, {1, "", "for (var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (var var1 of [1, 2]) { function foo() { var1; } }"}, {1, "", "for (var var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (let var1 of [1, 2]) { function foo() { var1; } }"}, {1, "", "for (let var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (const var1 of [1, 2]) { function foo() { var1; } }"}, {1, "", "for (const var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (var1 of [1, 2]) { function foo() { var1 = 0; } }"}, {1, "", "for (var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (var var1 of [1, 2]) { function foo() { var1 = 0; } }"}, {1, "", "for (var var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (let var1 of [1, 2]) { function foo() { var1 = 0; } }"}, {1, "", "for (let var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (const var1 of [1, 2]) { function foo() { var1 = 0; } }"}, {1, "", "for (const var1 of [1, 2]) { function foo() { var1 = 0; } }"},
// For in loops // For in loops
{"", "for (var1 in {a: 6}) { }"}, {1, "", "for (var1 in {a: 6}) { }"},
{"", "for (var var1 in {a: 6}) { }"}, {1, "", "for (var var1 in {a: 6}) { }"},
{"", "for (let var1 in {a: 6}) { }"}, {1, "", "for (let var1 in {a: 6}) { }"},
{"", "for (const var1 in {a: 6}) { }"}, {1, "", "for (const var1 in {a: 6}) { }"},
{"", "for (var1 in {a: 6}) { var1; }"}, {1, "", "for (var1 in {a: 6}) { var1; }"},
{"", "for (var var1 in {a: 6}) { var1; }"}, {1, "", "for (var var1 in {a: 6}) { var1; }"},
{"", "for (let var1 in {a: 6}) { var1; }"}, {1, "", "for (let var1 in {a: 6}) { var1; }"},
{"", "for (const var1 in {a: 6}) { var1; }"}, {1, "", "for (const var1 in {a: 6}) { var1; }"},
{"", "for (var1 in {a: 6}) { var1 = 0; }"}, {1, "", "for (var1 in {a: 6}) { var1 = 0; }"},
{"", "for (var var1 in {a: 6}) { var1 = 0; }"}, {1, "", "for (var var1 in {a: 6}) { var1 = 0; }"},
{"", "for (let var1 in {a: 6}) { var1 = 0; }"}, {1, "", "for (let var1 in {a: 6}) { var1 = 0; }"},
{"", "for (const var1 in {a: 6}) { var1 = 0; }"}, {1, "", "for (const var1 in {a: 6}) { var1 = 0; }"},
{"", "for (var1 in {a: 6}) { function foo() { var1; } }"}, {1, "", "for (var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1; } }"}, {1, "", "for (var var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1; } }"}, {1, "", "for (let var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1; } }"}, {1, "", "for (const var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"}, {1, "", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
// Loops without declarations // Loops without declarations
{"", "var var1 = 0; for ( ; var1 < 2; ++var1) { }"}, {1, "", "var var1 = 0; for ( ; var1 < 2; ++var1) { }"},
{"", {1, "",
"var var1 = 0; for ( ; var1 < 2; ++var1) { function foo() { var1; } }"}, "var var1 = 0; for ( ; var1 < 2; ++var1) { function foo() { var1; } }"},
{"", "var var1 = 0; for ( ; var1 > 2; ) { }"}, {1, "", "var var1 = 0; for ( ; var1 > 2; ) { }"},
{"", "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1; } }"}, {1, "", "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1; } }"},
{"", {1, "",
"var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1 = 6; } }"}, "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1 = 6; } }"},
{"", "var var1 = 0; for(var1; var1 < 2; ++var1) { }"}, {1, "", "var var1 = 0; for(var1; var1 < 2; ++var1) { }"},
{"", {1, "",
"var var1 = 0; for (var1; var1 < 2; ++var1) { function foo() { var1; } " "var var1 = 0; for (var1; var1 < 2; ++var1) { function foo() { var1; } "
"}"}, "}"},
{"", "var var1 = 0; for (var1; var1 > 2; ) { }"}, {1, "", "var var1 = 0; for (var1; var1 > 2; ) { }"},
{"", "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1; } }"}, {1, "",
{"", "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1; } }"},
{1, "",
"var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1 = 6; } }"}, "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1 = 6; } }"},
// Sloppy block functions. // Sloppy block functions.
{"", "if (true) { function f1() {} }"}, {1, "", "if (true) { function f1() {} }"},
{"", "if (true) { function f1() {} function f1() {} }"}, {1, "", "if (true) { function f1() {} function f1() {} }"},
{"", "if (true) { if (true) { function f1() {} } }"}, {1, "", "if (true) { if (true) { function f1() {} } }"},
{"", "if (true) { if (true) { function f1() {} function f1() {} } }"}, {1, "", "if (true) { if (true) { function f1() {} function f1() {} } }"},
{"", "if (true) { function f1() {} f1 = 3; }"}, {1, "", "if (true) { function f1() {} f1 = 3; }"},
{"", "if (true) { function f1() {} function foo() { f1; } }"}, {1, "", "if (true) { function f1() {} function foo() { f1; } }"},
{"", "if (true) { function f1() {} } function foo() { f1; }"}, {1, "", "if (true) { function f1() {} } function foo() { f1; }"},
{"", {1, "",
"if (true) { function f1() {} function f1() {} function foo() { f1; } " "if (true) { function f1() {} function f1() {} function foo() { f1; } "
"}"}, "}"},
{"", {1, "",
"if (true) { function f1() {} function f1() {} } function foo() { f1; " "if (true) { function f1() {} function f1() {} } function foo() { f1; "
"}"}, "}"},
{"", {1, "",
"if (true) { if (true) { function f1() {} } function foo() { f1; } }"}, "if (true) { if (true) { function f1() {} } function foo() { f1; } }"},
{"", {1, "",
"if (true) { if (true) { function f1() {} function f1() {} } function " "if (true) { if (true) { function f1() {} function f1() {} } function "
"foo() { f1; } }"}, "foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; function foo() { f1; } }"}, {1, "", "if (true) { function f1() {} f1 = 3; function foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; } function foo() { f1; }"}, {1, "", "if (true) { function f1() {} f1 = 3; } function foo() { f1; }"},
{"", "function inner2() { if (true) { function f1() {} } }"}, {1, "", "function inner2() { if (true) { function f1() {} } }"},
{"", "function inner2() { if (true) { function f1() {} f1 = 3; } }"}, {1, "", "function inner2() { if (true) { function f1() {} f1 = 3; } }"},
{"", "var f1 = 1; if (true) { function f1() {} }"}, {1, "", "var f1 = 1; if (true) { function f1() {} }"},
{"", "var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"}, {1, "",
"var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"},
}; };
for (unsigned i = 0; i < arraysize(inners); ++i) { for (unsigned i = 0; i < arraysize(inners); ++i) {
...@@ -358,6 +364,7 @@ TEST(PreParserScopeAnalysis) { ...@@ -358,6 +364,7 @@ TEST(PreParserScopeAnalysis) {
size_t index = 0; size_t index = 0;
i::ScopeTestHelper::CompareScopeToData( i::ScopeTestHelper::CompareScopeToData(
scope, lazy_info.preparsed_scope_data(), index); scope, lazy_info.preparsed_scope_data(), index,
inners[i].precise_maybe_assigned);
} }
} }
...@@ -32,7 +32,7 @@ class ScopeTestHelper { ...@@ -32,7 +32,7 @@ class ScopeTestHelper {
} }
static void CompareScopeToData(Scope* scope, const PreParsedScopeData* data, static void CompareScopeToData(Scope* scope, const PreParsedScopeData* data,
size_t& index) { size_t& index, bool precise_maybe_assigned) {
CHECK_EQ(data->backing_store_[index++], scope->scope_type()); CHECK_EQ(data->backing_store_[index++], scope->scope_type());
CHECK_EQ(data->backing_store_[index++], scope->start_position()); CHECK_EQ(data->backing_store_[index++], scope->start_position());
CHECK_EQ(data->backing_store_[index++], scope->end_position()); CHECK_EQ(data->backing_store_[index++], scope->end_position());
...@@ -70,14 +70,19 @@ class ScopeTestHelper { ...@@ -70,14 +70,19 @@ class ScopeTestHelper {
} }
#endif #endif
CHECK_EQ(data->backing_store_[index++], local->location()); CHECK_EQ(data->backing_store_[index++], local->location());
if (precise_maybe_assigned) {
CHECK_EQ(data->backing_store_[index++], local->maybe_assigned()); CHECK_EQ(data->backing_store_[index++], local->maybe_assigned());
} else {
STATIC_ASSERT(kMaybeAssigned > kNotAssigned);
CHECK_GE(data->backing_store_[index++], local->maybe_assigned());
}
} }
} }
for (Scope* inner = scope->inner_scope(); inner != nullptr; for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) { inner = inner->sibling()) {
if (!ScopeTreeIsHidden(inner)) { if (!ScopeTreeIsHidden(inner)) {
CompareScopeToData(inner, data, index); CompareScopeToData(inner, data, index, precise_maybe_assigned);
} }
} }
} }
......
...@@ -3495,6 +3495,365 @@ TEST(MaybeAssignedParameters) { ...@@ -3495,6 +3495,365 @@ TEST(MaybeAssignedParameters) {
} }
} }
struct Input {
bool assigned;
std::string source;
std::vector<unsigned> location; // "Directions" to the relevant scope.
};
static void TestMaybeAssigned(i::Zone* zone, Input input, const char* variable,
bool module, bool allow_lazy_parsing) {
i::Factory* factory = CcTest::i_isolate()->factory();
i::Handle<i::String> string =
factory->InternalizeUtf8String(input.source.c_str());
string->PrintOn(stdout);
printf("\n");
i::Handle<i::Script> script = factory->NewScript(string);
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_parsing);
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());
i::Variable* var;
{
// Find the variable.
for (auto it = input.location.begin(); it != input.location.end(); ++it) {
unsigned n = *it;
scope = scope->inner_scope();
while (n-- > 0) {
scope = scope->sibling();
}
}
CHECK_NOT_NULL(scope);
const i::AstRawString* var_name =
info->ast_value_factory()->GetOneByteString(variable);
var = scope->Lookup(var_name);
}
CHECK(var->is_used());
STATIC_ASSERT(true == i::kMaybeAssigned);
CHECK_EQ(input.assigned, var->maybe_assigned() == i::kMaybeAssigned);
}
static Input wrap(Input input) {
Input result;
result.assigned = input.assigned;
result.source = "function WRAPPED() { " + input.source + " }";
result.location.push_back(0);
for (auto n : input.location) {
result.location.push_back(n);
}
return result;
}
TEST(MaybeAssignedInsideLoop) {
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
LocalContext env;
i::Zone zone(isolate->allocator(), ZONE_NAME);
std::vector<unsigned> top; // Can't use {} in initializers below.
Input module_and_script_tests[] = {
{1, "for (j=x; j<10; ++j) { foo = j }", top},
{1, "for (j=x; j<10; ++j) { [foo] = [j] }", top},
{1, "for (j=x; j<10; ++j) { var foo = j }", top},
{1, "for (j=x; j<10; ++j) { var [foo] = [j] }", top},
{0, "for (j=x; j<10; ++j) { let foo = j }", {0}},
{0, "for (j=x; j<10; ++j) { let [foo] = [j] }", {0}},
{0, "for (j=x; j<10; ++j) { const foo = j }", {0}},
{0, "for (j=x; j<10; ++j) { const [foo] = [j] }", {0}},
{0, "for (j=x; j<10; ++j) { function foo() {return j} }", {0}},
{1, "for ({j}=x; j<10; ++j) { foo = j }", top},
{1, "for ({j}=x; j<10; ++j) { [foo] = [j] }", top},
{1, "for ({j}=x; j<10; ++j) { var foo = j }", top},
{1, "for ({j}=x; j<10; ++j) { var [foo] = [j] }", top},
{0, "for ({j}=x; j<10; ++j) { let foo = j }", {0}},
{0, "for ({j}=x; j<10; ++j) { let [foo] = [j] }", {0}},
{0, "for ({j}=x; j<10; ++j) { const foo = j }", {0}},
{0, "for ({j}=x; j<10; ++j) { const [foo] = [j] }", {0}},
{0, "for ({j}=x; j<10; ++j) { function foo() {return j} }", {0}},
{1, "for (var j=x; j<10; ++j) { foo = j }", top},
{1, "for (var j=x; j<10; ++j) { [foo] = [j] }", top},
{1, "for (var j=x; j<10; ++j) { var foo = j }", top},
{1, "for (var j=x; j<10; ++j) { var [foo] = [j] }", top},
{0, "for (var j=x; j<10; ++j) { let foo = j }", {0}},
{0, "for (var j=x; j<10; ++j) { let [foo] = [j] }", {0}},
{0, "for (var j=x; j<10; ++j) { const foo = j }", {0}},
{0, "for (var j=x; j<10; ++j) { const [foo] = [j] }", {0}},
{0, "for (var j=x; j<10; ++j) { function foo() {return j} }", {0}},
{1, "for (var {j}=x; j<10; ++j) { foo = j }", top},
{1, "for (var {j}=x; j<10; ++j) { [foo] = [j] }", top},
{1, "for (var {j}=x; j<10; ++j) { var foo = j }", top},
{1, "for (var {j}=x; j<10; ++j) { var [foo] = [j] }", top},
{0, "for (var {j}=x; j<10; ++j) { let foo = j }", {0}},
{0, "for (var {j}=x; j<10; ++j) { let [foo] = [j] }", {0}},
{0, "for (var {j}=x; j<10; ++j) { const foo = j }", {0}},
{0, "for (var {j}=x; j<10; ++j) { const [foo] = [j] }", {0}},
{0, "for (var {j}=x; j<10; ++j) { function foo() {return j} }", {0}},
{1, "for (let j=x; j<10; ++j) { foo = j }", top},
{1, "for (let j=x; j<10; ++j) { [foo] = [j] }", top},
{1, "for (let j=x; j<10; ++j) { var foo = j }", top},
{1, "for (let j=x; j<10; ++j) { var [foo] = [j] }", top},
{0, "for (let j=x; j<10; ++j) { let foo = j }", {0, 0, 0}},
{0, "for (let j=x; j<10; ++j) { let [foo] = [j] }", {0, 0, 0}},
{0, "for (let j=x; j<10; ++j) { const foo = j }", {0, 0, 0}},
{0, "for (let j=x; j<10; ++j) { const [foo] = [j] }", {0, 0, 0}},
{0, "for (let j=x; j<10; ++j) { function foo() {return j} }", {0, 0, 0}},
{1, "for (let {j}=x; j<10; ++j) { foo = j }", top},
{1, "for (let {j}=x; j<10; ++j) { [foo] = [j] }", top},
{1, "for (let {j}=x; j<10; ++j) { var foo = j }", top},
{1, "for (let {j}=x; j<10; ++j) { var [foo] = [j] }", top},
{0, "for (let {j}=x; j<10; ++j) { let foo = j }", {0, 0, 0}},
{0, "for (let {j}=x; j<10; ++j) { let [foo] = [j] }", {0, 0, 0}},
{0, "for (let {j}=x; j<10; ++j) { const foo = j }", {0, 0, 0}},
{0, "for (let {j}=x; j<10; ++j) { const [foo] = [j] }", {0, 0, 0}},
{0, "for (let {j}=x; j<10; ++j) { function foo(){return j} }", {0, 0, 0}},
{1, "for (j of x) { foo = j }", top},
{1, "for (j of x) { [foo] = [j] }", top},
{1, "for (j of x) { var foo = j }", top},
{1, "for (j of x) { var [foo] = [j] }", top},
{0, "for (j of x) { let foo = j }", {0}},
{0, "for (j of x) { let [foo] = [j] }", {0}},
{0, "for (j of x) { const foo = j }", {0}},
{0, "for (j of x) { const [foo] = [j] }", {0}},
{0, "for (j of x) { function foo() {return j} }", {0}},
{1, "for ({j} of x) { foo = j }", top},
{1, "for ({j} of x) { [foo] = [j] }", top},
{1, "for ({j} of x) { var foo = j }", top},
{1, "for ({j} of x) { var [foo] = [j] }", top},
{0, "for ({j} of x) { let foo = j }", {0}},
{0, "for ({j} of x) { let [foo] = [j] }", {0}},
{0, "for ({j} of x) { const foo = j }", {0}},
{0, "for ({j} of x) { const [foo] = [j] }", {0}},
{0, "for ({j} of x) { function foo() {return j} }", {0}},
{1, "for (var j of x) { foo = j }", top},
{1, "for (var j of x) { [foo] = [j] }", top},
{1, "for (var j of x) { var foo = j }", top},
{1, "for (var j of x) { var [foo] = [j] }", top},
{0, "for (var j of x) { let foo = j }", {0}},
{0, "for (var j of x) { let [foo] = [j] }", {0}},
{0, "for (var j of x) { const foo = j }", {0}},
{0, "for (var j of x) { const [foo] = [j] }", {0}},
{0, "for (var j of x) { function foo() {return j} }", {0}},
{1, "for (var {j} of x) { foo = j }", top},
{1, "for (var {j} of x) { [foo] = [j] }", top},
{1, "for (var {j} of x) { var foo = j }", top},
{1, "for (var {j} of x) { var [foo] = [j] }", top},
{0, "for (var {j} of x) { let foo = j }", {0}},
{0, "for (var {j} of x) { let [foo] = [j] }", {0}},
{0, "for (var {j} of x) { const foo = j }", {0}},
{0, "for (var {j} of x) { const [foo] = [j] }", {0}},
{0, "for (var {j} of x) { function foo() {return j} }", {0}},
{1, "for (let j of x) { foo = j }", top},
{1, "for (let j of x) { [foo] = [j] }", top},
{1, "for (let j of x) { var foo = j }", top},
{1, "for (let j of x) { var [foo] = [j] }", top},
{0, "for (let j of x) { let foo = j }", {0, 2, 0}},
{0, "for (let j of x) { let [foo] = [j] }", {0, 2, 0}},
{0, "for (let j of x) { const foo = j }", {0, 2, 0}},
{0, "for (let j of x) { const [foo] = [j] }", {0, 2, 0}},
{0, "for (let j of x) { function foo() {return j} }", {0, 2, 0}},
{1, "for (let {j} of x) { foo = j }", top},
{1, "for (let {j} of x) { [foo] = [j] }", top},
{1, "for (let {j} of x) { var foo = j }", top},
{1, "for (let {j} of x) { var [foo] = [j] }", top},
{0, "for (let {j} of x) { let foo = j }", {0, 2, 0}},
{0, "for (let {j} of x) { let [foo] = [j] }", {0, 2, 0}},
{0, "for (let {j} of x) { const foo = j }", {0, 2, 0}},
{0, "for (let {j} of x) { const [foo] = [j] }", {0, 2, 0}},
{0, "for (let {j} of x) { function foo() {return j} }", {0, 2, 0}},
{1, "for (const j of x) { foo = j }", top},
{1, "for (const j of x) { [foo] = [j] }", top},
{1, "for (const j of x) { var foo = j }", top},
{1, "for (const j of x) { var [foo] = [j] }", top},
{0, "for (const j of x) { let foo = j }", {0, 2, 0}},
{0, "for (const j of x) { let [foo] = [j] }", {0, 2, 0}},
{0, "for (const j of x) { const foo = j }", {0, 2, 0}},
{0, "for (const j of x) { const [foo] = [j] }", {0, 2, 0}},
{0, "for (const j of x) { function foo() {return j} }", {0, 2, 0}},
{1, "for (const {j} of x) { foo = j }", top},
{1, "for (const {j} of x) { [foo] = [j] }", top},
{1, "for (const {j} of x) { var foo = j }", top},
{1, "for (const {j} of x) { var [foo] = [j] }", top},
{0, "for (const {j} of x) { let foo = j }", {0, 2, 0}},
{0, "for (const {j} of x) { let [foo] = [j] }", {0, 2, 0}},
{0, "for (const {j} of x) { const foo = j }", {0, 2, 0}},
{0, "for (const {j} of x) { const [foo] = [j] }", {0, 2, 0}},
{0, "for (const {j} of x) { function foo() {return j} }", {0, 2, 0}},
{1, "for (j in x) { foo = j }", top},
{1, "for (j in x) { [foo] = [j] }", top},
{1, "for (j in x) { var foo = j }", top},
{1, "for (j in x) { var [foo] = [j] }", top},
{0, "for (j in x) { let foo = j }", {0}},
{0, "for (j in x) { let [foo] = [j] }", {0}},
{0, "for (j in x) { const foo = j }", {0}},
{0, "for (j in x) { const [foo] = [j] }", {0}},
{0, "for (j in x) { function foo() {return j} }", {0}},
{1, "for ({j} in x) { foo = j }", top},
{1, "for ({j} in x) { [foo] = [j] }", top},
{1, "for ({j} in x) { var foo = j }", top},
{1, "for ({j} in x) { var [foo] = [j] }", top},
{0, "for ({j} in x) { let foo = j }", {0}},
{0, "for ({j} in x) { let [foo] = [j] }", {0}},
{0, "for ({j} in x) { const foo = j }", {0}},
{0, "for ({j} in x) { const [foo] = [j] }", {0}},
{0, "for ({j} in x) { function foo() {return j} }", {0}},
{1, "for (var j in x) { foo = j }", top},
{1, "for (var j in x) { [foo] = [j] }", top},
{1, "for (var j in x) { var foo = j }", top},
{1, "for (var j in x) { var [foo] = [j] }", top},
{0, "for (var j in x) { let foo = j }", {0}},
{0, "for (var j in x) { let [foo] = [j] }", {0}},
{0, "for (var j in x) { const foo = j }", {0}},
{0, "for (var j in x) { const [foo] = [j] }", {0}},
{0, "for (var j in x) { function foo() {return j} }", {0}},
{1, "for (var {j} in x) { foo = j }", top},
{1, "for (var {j} in x) { [foo] = [j] }", top},
{1, "for (var {j} in x) { var foo = j }", top},
{1, "for (var {j} in x) { var [foo] = [j] }", top},
{0, "for (var {j} in x) { let foo = j }", {0}},
{0, "for (var {j} in x) { let [foo] = [j] }", {0}},
{0, "for (var {j} in x) { const foo = j }", {0}},
{0, "for (var {j} in x) { const [foo] = [j] }", {0}},
{0, "for (var {j} in x) { function foo() {return j} }", {0}},
{1, "for (let j in x) { foo = j }", top},
{1, "for (let j in x) { [foo] = [j] }", top},
{1, "for (let j in x) { var foo = j }", top},
{1, "for (let j in x) { var [foo] = [j] }", top},
{0, "for (let j in x) { let foo = j }", {0, 0, 0}},
{0, "for (let j in x) { let [foo] = [j] }", {0, 0, 0}},
{0, "for (let j in x) { const foo = j }", {0, 0, 0}},
{0, "for (let j in x) { const [foo] = [j] }", {0, 0, 0}},
{0, "for (let j in x) { function foo() {return j} }", {0, 0, 0}},
{1, "for (let {j} in x) { foo = j }", top},
{1, "for (let {j} in x) { [foo] = [j] }", top},
{1, "for (let {j} in x) { var foo = j }", top},
{1, "for (let {j} in x) { var [foo] = [j] }", top},
{0, "for (let {j} in x) { let foo = j }", {0, 0, 0}},
{0, "for (let {j} in x) { let [foo] = [j] }", {0, 0, 0}},
{0, "for (let {j} in x) { const foo = j }", {0, 0, 0}},
{0, "for (let {j} in x) { const [foo] = [j] }", {0, 0, 0}},
{0, "for (let {j} in x) { function foo() {return j} }", {0, 0, 0}},
{1, "for (const j in x) { foo = j }", top},
{1, "for (const j in x) { [foo] = [j] }", top},
{1, "for (const j in x) { var foo = j }", top},
{1, "for (const j in x) { var [foo] = [j] }", top},
{0, "for (const j in x) { let foo = j }", {0, 0, 0}},
{0, "for (const j in x) { let [foo] = [j] }", {0, 0, 0}},
{0, "for (const j in x) { const foo = j }", {0, 0, 0}},
{0, "for (const j in x) { const [foo] = [j] }", {0, 0, 0}},
{0, "for (const j in x) { function foo() {return j} }", {0, 0, 0}},
{1, "for (const {j} in x) { foo = j }", top},
{1, "for (const {j} in x) { [foo] = [j] }", top},
{1, "for (const {j} in x) { var foo = j }", top},
{1, "for (const {j} in x) { var [foo] = [j] }", top},
{0, "for (const {j} in x) { let foo = j }", {0, 0, 0}},
{0, "for (const {j} in x) { let [foo] = [j] }", {0, 0, 0}},
{0, "for (const {j} in x) { const foo = j }", {0, 0, 0}},
{0, "for (const {j} in x) { const [foo] = [j] }", {0, 0, 0}},
{0, "for (const {j} in x) { function foo() {return j} }", {0, 0, 0}},
{1, "while (j) { foo = j }", top},
{1, "while (j) { [foo] = [j] }", top},
{1, "while (j) { var foo = j }", top},
{1, "while (j) { var [foo] = [j] }", top},
{0, "while (j) { let foo = j }", {0}},
{0, "while (j) { let [foo] = [j] }", {0}},
{0, "while (j) { const foo = j }", {0}},
{0, "while (j) { const [foo] = [j] }", {0}},
{0, "while (j) { function foo() {return j} }", {0}},
{1, "do { foo = j } while (j)", top},
{1, "do { [foo] = [j] } while (j)", top},
{1, "do { var foo = j } while (j)", top},
{1, "do { var [foo] = [j] } while (j)", top},
{0, "do { let foo = j } while (j)", {0}},
{0, "do { let [foo] = [j] } while (j)", {0}},
{0, "do { const foo = j } while (j)", {0}},
{0, "do { const [foo] = [j] } while (j)", {0}},
{0, "do { function foo() {return j} } while (j)", {0}},
};
Input script_only_tests[] = {
{1, "for (j=x; j<10; ++j) { function foo() {return j} }", top},
{1, "for ({j}=x; j<10; ++j) { function foo() {return j} }", top},
{1, "for (var j=x; j<10; ++j) { function foo() {return j} }", top},
{1, "for (var {j}=x; j<10; ++j) { function foo() {return j} }", top},
{1, "for (let j=x; j<10; ++j) { function foo() {return j} }", top},
{1, "for (let {j}=x; j<10; ++j) { function foo() {return j} }", top},
{1, "for (j of x) { function foo() {return j} }", top},
{1, "for ({j} of x) { function foo() {return j} }", top},
{1, "for (var j of x) { function foo() {return j} }", top},
{1, "for (var {j} of x) { function foo() {return j} }", top},
{1, "for (let j of x) { function foo() {return j} }", top},
{1, "for (let {j} of x) { function foo() {return j} }", top},
{1, "for (const j of x) { function foo() {return j} }", top},
{1, "for (const {j} of x) { function foo() {return j} }", top},
{1, "for (j in x) { function foo() {return j} }", top},
{1, "for ({j} in x) { function foo() {return j} }", top},
{1, "for (var j in x) { function foo() {return j} }", top},
{1, "for (var {j} in x) { function foo() {return j} }", top},
{1, "for (let j in x) { function foo() {return j} }", top},
{1, "for (let {j} in x) { function foo() {return j} }", top},
{1, "for (const j in x) { function foo() {return j} }", top},
{1, "for (const {j} in x) { function foo() {return j} }", top},
{1, "while (j) { function foo() {return j} }", top},
{1, "do { function foo() {return j} } while (j)", top},
};
for (unsigned i = 0; i < arraysize(module_and_script_tests); ++i) {
Input input = module_and_script_tests[i];
for (unsigned module = 0; module <= 1; ++module) {
for (unsigned allow_lazy_parsing = 0; allow_lazy_parsing <= 1;
++allow_lazy_parsing) {
TestMaybeAssigned(&zone, input, "foo", module, allow_lazy_parsing);
}
TestMaybeAssigned(&zone, wrap(input), "foo", module, false);
}
}
for (unsigned i = 0; i < arraysize(script_only_tests); ++i) {
Input input = script_only_tests[i];
for (unsigned allow_lazy_parsing = 0; allow_lazy_parsing <= 1;
++allow_lazy_parsing) {
TestMaybeAssigned(&zone, input, "foo", false, allow_lazy_parsing);
}
TestMaybeAssigned(&zone, wrap(input), "foo", false, false);
}
}
TEST(MaybeAssignedTopLevel) { TEST(MaybeAssignedTopLevel) {
i::Isolate* isolate = CcTest::i_isolate(); i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
......
// Copyright 2016 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.
// Flags: --allow-natives-syntax --function-context-specialization
function f(n) {
var a = [];
function g() { return x }
for (var i = 0; i < n; ++i) {
var x = i;
a[i] = g;
%OptimizeFunctionOnNextCall(g);
g();
}
return a;
}
var a = f(3);
assertEquals(3, a.length);
assertEquals(2, a[0]());
assertEquals(2, a[1]());
assertEquals(2, a[2]());
// Copyright 2016 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.
// Flags: --allow-natives-syntax
function f(n) {
"use asm";
var a = [];
function g() { return x }
for (var i = 0; i < n; ++i) {
var x = i;
a[i] = g;
%OptimizeFunctionOnNextCall(g);
g();
}
return a;
}
var a = f(3);
assertEquals(3, a.length);
assertEquals(2, a[0]());
assertEquals(2, a[1]());
assertEquals(2, a[2]());
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