1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Flags: --harmony-scoping
29
30"use strict";
31
32// Test temporal dead zone semantics of let bound variables in
33// function and block scopes.
34
35function TestFunctionLocal(s) {
36  try {
37    eval("(function(){" + s + "; })")();
38  } catch (e) {
39    assertInstanceof(e, ReferenceError);
40    return;
41  }
42  assertUnreachable();
43}
44
45function TestBlockLocal(s,e) {
46  try {
47    eval("(function(){ {" + s + ";} })")();
48  } catch (e) {
49    assertInstanceof(e, ReferenceError);
50    return;
51  }
52  assertUnreachable();
53}
54
55
56function TestAll(s) {
57  TestBlockLocal(s);
58  TestFunctionLocal(s);
59}
60
61// Use before initialization in declaration statement.
62TestAll('let x = x + 1');
63TestAll('let x = x += 1');
64TestAll('let x = x++');
65TestAll('let x = ++x');
66TestAll('const x = x + 1');
67
68// Use before initialization in prior statement.
69TestAll('x + 1; let x;');
70TestAll('x = 1; let x;');
71TestAll('x += 1; let x;');
72TestAll('++x; let x;');
73TestAll('x++; let x;');
74TestAll('let y = x; const x = 1;');
75
76TestAll('f(); let x; function f() { return x + 1; }');
77TestAll('f(); let x; function f() { x = 1; }');
78TestAll('f(); let x; function f() { x += 1; }');
79TestAll('f(); let x; function f() { ++x; }');
80TestAll('f(); let x; function f() { x++; }');
81TestAll('f(); const x = 1; function f() { return x; }');
82
83TestAll('f()(); let x; function f() { return function() { return x + 1; } }');
84TestAll('f()(); let x; function f() { return function() { x = 1; } }');
85TestAll('f()(); let x; function f() { return function() { x += 1; } }');
86TestAll('f()(); let x; function f() { return function() { ++x; } }');
87TestAll('f()(); let x; function f() { return function() { x++; } }');
88TestAll('f()(); const x = 1; function f() { return function() { return x; } }');
89
90// Use before initialization with a dynamic lookup.
91TestAll('eval("x + 1;"); let x;');
92TestAll('eval("x = 1;"); let x;');
93TestAll('eval("x += 1;"); let x;');
94TestAll('eval("++x;"); let x;');
95TestAll('eval("x++;"); let x;');
96TestAll('eval("x"); const x = 1;');
97
98// Use before initialization with check for eval-shadowed bindings.
99TestAll('function f() { eval("var y = 2;"); x + 1; }; f(); let x;');
100TestAll('function f() { eval("var y = 2;"); x = 1; }; f(); let x;');
101TestAll('function f() { eval("var y = 2;"); x += 1; }; f(); let x;');
102TestAll('function f() { eval("var y = 2;"); ++x; }; f(); let x;');
103TestAll('function f() { eval("var y = 2;"); x++; }; f(); let x;');
104
105// Test that variables introduced by function declarations are created and
106// initialized upon entering a function / block scope.
107function f() {
108  {
109    assertEquals(2, g1());
110    assertEquals(2, eval("g1()"));
111
112    // block scoped function declaration
113    function g1() {
114      return 2;
115    }
116  }
117
118  assertEquals(3, g2());
119  assertEquals(3, eval("g2()"));
120  // function scoped function declaration
121  function g2() {
122    return 3;
123  }
124}
125f();
126
127// Test that a function declaration introduces a block scoped variable.
128TestAll('{ function k() { return 0; } }; k(); ');
129
130// Test that a function declaration sees the scope it resides in.
131function f2() {
132  let m, n, o, p;
133  {
134    m = g;
135    function g() {
136      return a;
137    }
138    let a = 1;
139  }
140  assertEquals(1, m());
141
142  try {
143    throw 2;
144  } catch(b) {
145    n = h;
146    function h() {
147      return b + c;
148    }
149    let c = 3;
150  }
151  assertEquals(5, n());
152
153  {
154    o = i;
155    function i() {
156      return d;
157    }
158    let d = 4;
159  }
160  assertEquals(4, o());
161
162  try {
163    throw 5;
164  } catch(e) {
165    p = j;
166    function j() {
167      return e + f;
168    }
169    let f = 6;
170  }
171  assertEquals(11, p());
172}
173f2();
174
175// Test that resolution of let bound variables works with scopes that call eval.
176function outer() {
177  function middle() {
178    function inner() {
179      return x;
180    }
181    eval("1 + 1");
182    return x + inner();
183  }
184
185  let x = 1;
186  return middle();
187}
188
189assertEquals(2, outer());
190