• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
16function 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