Home | History | Annotate | Download | only in strong
      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