OLD | NEW |
| (Empty) |
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. | |
4 | |
5 // Flags: --strong-mode | |
6 | |
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). | |
12 | |
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) { | |
17 "use strict"; | |
18 let prologue = "(function outer() { if (false) { "; | |
19 let epilogue = " } })();"; | |
20 | |
21 assertThrows("'use strong'; " + prologue + code + epilogue, ReferenceError); | |
22 | |
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); | |
26 } | |
27 | |
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;"); | |
35 | |
36 assertThrowsHelper("x; const x = 0;"); | |
37 assertThrowsHelper("function f() { x; const x = 0; }"); | |
38 assertThrowsHelper("function f() { x; } const x = 0;"); | |
39 | |
40 // These tests needs to be done a bit more manually, since var is not allowed | |
41 // in strong mode: | |
42 assertThrows( | |
43 `(function outer() { | |
44 function f() { 'use strong'; if (false) { x; } } var x = 0; f(); | |
45 })()`, | |
46 ReferenceError); | |
47 assertDoesNotThrow( | |
48 "(function outer() {\n" + | |
49 " function f() { if (false) { x; } } var x = 0; f(); \n" + | |
50 "})()"); | |
51 | |
52 assertThrows( | |
53 "(function outer() {\n" + | |
54 " function f() { 'use strong'; if (false) { x; } } var x; f(); \n" + | |
55 "})()", | |
56 ReferenceError); | |
57 assertDoesNotThrow( | |
58 "(function outer() {\n" + | |
59 " function f() { if (false) { x; } } var x; f(); \n" + | |
60 "})()"); | |
61 | |
62 // Use occurring in the initializer of the declaration: | |
63 assertThrowsHelper("let x = x + 1;"); | |
64 assertThrowsHelper("let x = x;"); | |
65 assertThrowsHelper("let x = y, y = 4;"); | |
66 assertThrowsHelper("let x = function() { x; }"); | |
67 assertThrowsHelper("let x = a => { x; }"); | |
68 assertThrowsHelper("function f(x) { return x; }; let x = f(x);"); | |
69 assertThrowsHelper("const x = x;"); | |
70 assertThrowsHelper("const x = function() { x; }"); | |
71 assertThrowsHelper("const x = a => { x; }"); | |
72 assertThrowsHelper("function f(x) {return x}; const x = f(x);"); | |
73 | |
74 assertThrowsHelper("for (let x = x; ; ) { }"); | |
75 assertThrowsHelper("for (const x = x; ; ) { }"); | |
76 assertThrowsHelper("for (let x = y, y; ; ) { }"); | |
77 assertThrowsHelper("for (const x = y, y = 0; ; ) { }"); | |
78 | |
79 // Computed property names | |
80 assertThrowsHelper("let o = { 'a': 'b', [o.a]: 'c'};"); | |
81 })(); | |
82 | |
83 | |
84 (function DeclarationAfterUseInClasses() { | |
85 // Referring to a variable declared later | |
86 assertThrowsHelper("class C { m() { x; } } let x = 0;"); | |
87 assertThrowsHelper("class C { static m() { x; } } let x = 0;"); | |
88 assertThrowsHelper("class C { [x]() { } } let x = 0;"); | |
89 | |
90 assertThrowsHelper("class C { m() { x; } } const x = 0;"); | |
91 assertThrowsHelper("class C { static m() { x; } } const x = 0;"); | |
92 assertThrowsHelper("class C { [x]() { } } const x = 0;"); | |
93 | |
94 // Referring to the class name. | |
95 assertThrowsHelper("class C extends C { }"); | |
96 assertThrowsHelper("let C = class C2 extends C { }"); | |
97 assertThrowsHelper("let C = class C2 extends C2 { }"); | |
98 | |
99 assertThrowsHelper("let C = class C2 { constructor() { C; } }"); | |
100 assertThrowsHelper("let C = class C2 { method() { C; } }"); | |
101 assertThrowsHelper("let C = class C2 { *generator_method() { C; } }"); | |
102 | |
103 assertThrowsHelper( | |
104 `let C = class C2 { | |
105 static a() { return 'A'; } | |
106 [C.a()]() { return 'B'; } | |
107 };`); | |
108 | |
109 assertThrowsHelper( | |
110 `let C = class C2 { | |
111 static a() { return 'A'; } | |
112 [C2.a()]() { return 'B'; } | |
113 };`); | |
114 | |
115 assertThrowsHelper( | |
116 `let C = class C2 { | |
117 [(function() { C; return 'A';})()]() { return 'B'; } | |
118 };`); | |
119 | |
120 // The reference to C or C2 is inside a function, but not a method. | |
121 assertThrowsHelper( | |
122 `let C = class C2 { | |
123 [(function() { C2; return 'A';})()]() { return 'B'; } | |
124 };`); | |
125 | |
126 assertThrowsHelper( | |
127 `let C = class C2 { | |
128 [(function() { C; return 'A';})()]() { return 'B'; } | |
129 };`); | |
130 | |
131 // The reference to C or C2 is inside a method, but it's not a method of the | |
132 // relevant class (C2). | |
133 assertThrowsHelper( | |
134 `let C = class C2 { | |
135 [(new (class D { m() { C2; return 'A'; } })).m()]() { | |
136 return 'B'; | |
137 } | |
138 }`); | |
139 | |
140 assertThrowsHelper( | |
141 `let C = class C2 { | |
142 [(new (class D { m() { C; return 'A'; } })).m()]() { | |
143 return 'B'; | |
144 } | |
145 }`); | |
146 | |
147 assertThrowsHelper( | |
148 `let C = class C2 { | |
149 [({m() { C2; return 'A'; }}).m()]() { return 'B'; } | |
150 }`); | |
151 | |
152 assertThrowsHelper( | |
153 `let C = class C2 { | |
154 [({m() { C; return 'A'; }}).m()]() { return 'B'; } | |
155 }`); | |
156 | |
157 assertThrowsHelper( | |
158 `class COuter { | |
159 m() { | |
160 class CInner { | |
161 [({ m() { CInner; return 'A'; } }).m()]() { | |
162 return 'B'; | |
163 } | |
164 } | |
165 } | |
166 }`); | |
167 })(); | |
168 | |
169 | |
170 (function UsesWhichAreFine() { | |
171 "use strong"; | |
172 | |
173 let var1 = 0; | |
174 var1; | |
175 | |
176 let var2a = 0, var2b = var2a + 1, var2c = 2 + var2b; | |
177 | |
178 for (let var3 = 0; var3 < 1; var3++) { | |
179 var3; | |
180 } | |
181 | |
182 for (let var4a = 0, var4b = var4a; var4a + var4b < 4; var4a++, var4b++) { | |
183 var4a; | |
184 var4b; | |
185 } | |
186 | |
187 let var5 = 5; | |
188 for (; var5 < 10; ++var5) { } | |
189 | |
190 let arr = [1, 2]; | |
191 for (let i of arr) { | |
192 i; | |
193 } | |
194 | |
195 try { | |
196 throw "error"; | |
197 } catch (e) { | |
198 e; | |
199 } | |
200 | |
201 function func1() { func1; this; } | |
202 func1(); | |
203 func1; | |
204 | |
205 function * func2() { func2; this; } | |
206 func2(); | |
207 func2; | |
208 | |
209 function func4(p, ...rest) { p; rest; this; func2; } | |
210 // TODO(arv): The arity checking is not correct with rest parameters. | |
211 func4(1, 2); | |
212 | |
213 let func5 = (p1, p2) => { p1; p2; }; | |
214 func5(1, 2); | |
215 | |
216 let func5b = p1 => p1; | |
217 func5b(1); | |
218 | |
219 function func6() { | |
220 var1, var2a, var2b, var2c; | |
221 } | |
222 | |
223 class C1 { constructor() { C1; } }; new C1(); | |
224 let C2 = class C3 { constructor() { C3; } }; new C2(); | |
225 | |
226 class C4 { method() { C4; } *generator_method() { C4; } }; new C4(); | |
227 let C5 = class C6 { method() { C6; } *generator_method() { C6; } }; new C5(); | |
228 | |
229 class C7 { static method() { C7; } }; new C7(); | |
230 let C8 = class C9 { static method() { C9; } }; new C8(); | |
231 | |
232 class C10 { get x() { C10; } }; new C10(); | |
233 let C11 = class C12 { get x() { C12; } }; new C11(); | |
234 | |
235 // Regression test for unnamed classes. | |
236 let C13 = class { m() { var1; } }; | |
237 | |
238 class COuter { | |
239 m() { | |
240 class CInner { | |
241 // Here we can refer to COuter but not to CInner (see corresponding | |
242 // assertion test): | |
243 [({ m() { COuter; return 'A'; } }).m()]() { return 'B'; } | |
244 // And here we can refer to both: | |
245 n() { COuter; CInner; } | |
246 } | |
247 return new CInner(); | |
248 } | |
249 } | |
250 (new COuter()).m().n(); | |
251 | |
252 // Making sure the check which is supposed to prevent "object literal inside | |
253 // computed property name references the class name" is not too generic: | |
254 class C14 { m() { let obj = { n() { C14 } }; obj.n(); } }; (new C14()).m(); | |
255 })(); | |
OLD | NEW |