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// We want to test the context chain shape.  In each of the tests cases
33// below, the outer with is to force a runtime lookup of the identifier 'x'
34// to actually verify that the inner context has been discarded.  A static
35// lookup of 'x' might accidentally succeed.
36
37{
38  let x = 2;
39  L: {
40    let x = 3;
41    assertEquals(3, x);
42    break L;
43    assertTrue(false);
44  }
45  assertEquals(2, x);
46}
47
48do {
49  let x = 4;
50  assertEquals(4,x);
51  {
52    let x = 5;
53    assertEquals(5, x);
54    continue;
55    assertTrue(false);
56  }
57} while (false);
58
59var caught = false;
60try {
61  {
62    let xx = 18;
63    throw 25;
64    assertTrue(false);
65  }
66} catch (e) {
67  caught = true;
68  assertEquals(25, e);
69  (function () {
70    try {
71      // NOTE: This checks that the block scope containing xx has been
72      // removed from the context chain.
73      eval('xx');
74      assertTrue(false);  // should not reach here
75    } catch (e2) {
76      assertTrue(e2 instanceof ReferenceError);
77    }
78  })();
79}
80assertTrue(caught);
81
82
83(function(x) {
84  label: {
85    let x = 'inner';
86    break label;
87  }
88  assertEquals('outer', eval('x'));
89})('outer');
90
91
92(function(x) {
93  label: {
94    let x = 'middle';
95    {
96      let x = 'inner';
97      break label;
98    }
99  }
100  assertEquals('outer', eval('x'));
101})('outer');
102
103
104(function(x) {
105  for (var i = 0; i < 10; ++i) {
106    let x = 'inner' + i;
107    continue;
108  }
109  assertEquals('outer', eval('x'));
110})('outer');
111
112
113(function(x) {
114  label: for (var i = 0; i < 10; ++i) {
115    let x = 'middle' + i;
116    for (var j = 0; j < 10; ++j) {
117      let x = 'inner' + j;
118      continue label;
119    }
120  }
121  assertEquals('outer', eval('x'));
122})('outer');
123
124
125(function(x) {
126  try {
127    let x = 'inner';
128    throw 0;
129  } catch (e) {
130    assertEquals('outer', eval('x'));
131  }
132})('outer');
133
134
135(function(x) {
136  try {
137    let x = 'middle';
138    {
139      let x = 'inner';
140      throw 0;
141    }
142  } catch (e) {
143    assertEquals('outer', eval('x'));
144  }
145})('outer');
146
147
148try {
149  (function(x) {
150    try {
151      let x = 'inner';
152      throw 0;
153    } finally {
154      assertEquals('outer', eval('x'));
155    }
156  })('outer');
157} catch (e) {
158  if (e instanceof MjsUnitAssertionError) throw e;
159}
160
161
162try {
163  (function(x) {
164    try {
165      let x = 'middle';
166      {
167        let x = 'inner';
168        throw 0;
169      }
170    } finally {
171      assertEquals('outer', eval('x'));
172    }
173  })('outer');
174} catch (e) {
175  if (e instanceof MjsUnitAssertionError) throw e;
176}
177
178
179// Verify that the context is correctly set in the stack frame after exiting
180// from with.
181function f() {}
182
183(function(x) {
184  label: {
185    let x = 'inner';
186    break label;
187  }
188  f();  // The context could be restored from the stack after the call.
189  assertEquals('outer', eval('x'));
190})('outer');
191
192
193(function(x) {
194  for (var i = 0; i < 10; ++i) {
195    let x = 'inner';
196    continue;
197  }
198  f();
199  assertEquals('outer', eval('x'));
200})('outer');
201
202
203(function(x) {
204  try {
205    let x = 'inner';
206    throw 0;
207  } catch (e) {
208    f();
209    assertEquals('outer', eval('x'));
210  }
211})('outer');
212
213
214try {
215  (function(x) {
216    try {
217      let x = 'inner';
218      throw 0;
219    } finally {
220      f();
221      assertEquals('outer', eval('x'));
222    }
223  })('outer');
224} catch (e) {
225  if (e instanceof MjsUnitAssertionError) throw e;
226}
227