1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Flags: --strong-mode --harmony_rest_parameters --harmony_arrow_functions --harmony_classes --harmony_computed-property_names
7 // Note that it's essential for these tests that the reference is inside dead
8 // code (because we already produce ReferenceErrors for run-time unresolved
9 // variables and don't want to confuse those with strong mode errors). But the
10 // errors should *not* be inside lazy, unexecuted functions, since lazy parsing
11 // doesn't produce strong mode scoping errors).
13 // In addition, assertThrows will call eval and that changes variable binding
14 // types (see e.g., UNBOUND_EVAL_SHADOWED). We can avoid unwanted side effects
15 // by wrapping the code to be tested inside an outer function.
16 function assertThrowsHelper(code) {
18 let prologue = "(function outer() { if (false) { ";
19 let epilogue = " } })();";
21 assertThrows("'use strong'; " + prologue + code + epilogue, ReferenceError);
23 // Make sure the error happens only in strong mode (note that we need strict
24 // mode here because of let).
25 assertDoesNotThrow("'use strict'; " + prologue + code + epilogue);
28 (function DeclarationAfterUse() {
29 // Note that these tests only test cases where the declaration is found but is
30 // after the use. In particular, we cannot yet detect cases where the use can
31 // possibly bind to a global variable.
32 assertThrowsHelper("x; let x = 0;");
33 assertThrowsHelper("function f() { x; let x = 0; }");
34 assertThrowsHelper("function f() { x; } let x = 0;");
36 // These tests needs to be done a bit more manually, since var is not allowed
40 function f() { 'use strong'; if (false) { x; } } var x = 0; f();
44 "(function outer() {\n" +
45 " function f() { if (false) { x; } } var x = 0; f(); \n" +
49 "(function outer() {\n" +
50 " function f() { 'use strong'; if (false) { x; } } var x; f(); \n" +
54 "(function outer() {\n" +
55 " function f() { if (false) { x; } } var x; f(); \n" +
58 // Errors are also detected when the declaration and the use are in the same
60 assertThrows("'use strong'; eval('if (false) { x; let x = 0;}')",
62 assertDoesNotThrow("'use strict'; eval('if (false) { x; let x = 0; }')");
64 // Use occurring in the initializer of the declaration:
65 assertThrowsHelper("let x = x + 1;");
66 assertThrowsHelper("let x = x;");
67 assertThrowsHelper("let x = y, y = 4;");
68 assertThrowsHelper("let x = function() { x; }");
69 assertThrowsHelper("let x = a => { x; }");
70 assertThrowsHelper("function f(x) { return x; }; let x = f(x);");
71 assertThrowsHelper("const x = x;");
72 assertThrowsHelper("const x = function() { x; }");
73 assertThrowsHelper("const x = a => { x; }");
74 assertThrowsHelper("function f(x) {return x}; const x = f(x);");
76 assertThrowsHelper("for (let x = x; ; ) { }");
77 assertThrowsHelper("for (const x = x; ; ) { }");
78 assertThrowsHelper("for (let x = y, y; ; ) { }");
79 assertThrowsHelper("for (const x = y, y = 0; ; ) { }");
81 // Computed property names
82 assertThrowsHelper("let o = { 'a': 'b', [o.a]: 'c'};");
86 (function DeclarationAfterUseInClasses() {
87 assertThrowsHelper("class C extends C { }");
88 assertThrowsHelper("let C = class C2 extends C { }");
89 assertThrowsHelper("let C = class C2 extends C2 { }");
91 assertThrowsHelper("let C = class C2 { constructor() { C; } }");
92 assertThrowsHelper("let C = class C2 { method() { C; } }");
93 assertThrowsHelper("let C = class C2 { *generator_method() { C; } }");
97 static a() { return 'A'; }
98 [C.a()]() { return 'B'; }
103 static a() { return 'A'; }
104 [C2.a()]() { return 'B'; }
109 [(function() { C; return 'A';})()]() { return 'B'; }
112 // The reference to C or C2 is inside a function, but not a method.
115 [(function() { C2; return 'A';})()]() { return 'B'; }
120 [(function() { C; return 'A';})()]() { return 'B'; }
123 // The reference to C or C2 is inside a method, but it's not a method of the
124 // relevant class (C2).
127 [(new (class D { m() { C2; return 'A'; } })).m()]() {
134 [(new (class D { m() { C; return 'A'; } })).m()]() {
141 [({m() { C2; return 'A'; }}).m()]() { return 'B'; }
146 [({m() { C; return 'A'; }}).m()]() { return 'B'; }
153 [({ m() { CInner; return 'A'; } }).m()]() {
162 (function UsesWhichAreFine() {
168 let var2a = 0, var2b = var2a + 1, var2c = 2 + var2b;
170 for (let var3 = 0; var3 < 1; var3++) {
174 for (let var4a = 0, var4b = var4a; var4a + var4b < 4; var4a++, var4b++) {
180 for (; var5 < 10; ++var5) { }
188 // The second var6 resolves to outside (not to the first var6).
189 for (let var6 of var6) { var6; }
197 function func1() { func1; this; }
201 function * func2() { func2; this; }
205 function func4(p, ...rest) { p; rest; this; func2; }
208 let func5 = (p1, p2) => { p1; p2; };
211 let func5b = p1 => p1;
215 var1, var2a, var2b, var2c;
219 let var7 = 0; // Declaration position will be something large.
220 // But use position will be something small, however, this is not an error,
221 // since the use is inside an eval scope.
226 class C1 { constructor() { C1; } }; new C1();
227 let C2 = class C3 { constructor() { C3; } }; new C2();
229 class C4 { method() { C4; } *generator_method() { C4; } }; new C4();
230 let C5 = class C6 { method() { C6; } *generator_method() { C6; } }; new C5();
232 class C7 { static method() { C7; } }; new C7();
233 let C8 = class C9 { static method() { C9; } }; new C8();
235 class C10 { get x() { C10; } }; new C10();
236 let C11 = class C12 { get x() { C12; } }; new C11();
238 // Regression test for unnamed classes.
239 let C13 = class { m() { var1; } };
244 // Here we can refer to COuter but not to CInner (see corresponding
246 [({ m() { COuter; return 'A'; } }).m()]() { return 'B'; }
247 // And here we can refer to both:
248 n() { COuter; CInner; }
253 (new COuter()).m().n();
255 // Making sure the check which is supposed to prevent "object literal inside
256 // computed property name references the class name" is not too generic:
257 class C14 { m() { let obj = { n() { C14 } }; obj.n(); } }; (new C14()).m();