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 })(); 256