blob: 2bea1476abd033b28716feb86aea8727c8e9a4b2 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
Ben Murdochda12d292016-06-02 14:46:10 +01005// Flags: --harmony-sloppy --harmony-sloppy-let
6// Flags: --harmony-sloppy-function
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007
8// Test Annex B 3.3 semantics for functions declared in blocks in sloppy mode.
9// http://www.ecma-international.org/ecma-262/6.0/#sec-block-level-function-declarations-web-legacy-compatibility-semantics
10
11(function overridingLocalFunction() {
12 var x = [];
13 assertEquals('function', typeof f);
14 function f() {
15 x.push(1);
16 }
17 f();
18 {
19 f();
20 function f() {
21 x.push(2);
22 }
23 f();
24 }
25 f();
26 {
27 f();
28 function f() {
29 x.push(3);
30 }
31 f();
32 }
33 f();
34 assertArrayEquals([1, 2, 2, 2, 3, 3, 3], x);
35})();
36
37(function newFunctionBinding() {
38 var x = [];
39 assertEquals('undefined', typeof f);
40 {
41 f();
42 function f() {
43 x.push(2);
44 }
45 f();
46 }
47 f();
48 {
49 f();
50 function f() {
51 x.push(3);
52 }
53 f();
54 }
55 f();
56 assertArrayEquals([2, 2, 2, 3, 3, 3], x);
57})();
58
59(function shadowingLetDoesntBind() {
60 let f = 1;
61 assertEquals(1, f);
62 {
63 let y = 3;
64 function f() {
65 y = 2;
66 }
67 f();
68 assertEquals(2, y);
69 }
70 assertEquals(1, f);
71})();
72
73(function shadowingClassDoesntBind() {
74 class f { }
75 assertEquals('class f { }', f.toString());
76 {
77 let y = 3;
78 function f() {
79 y = 2;
80 }
81 f();
82 assertEquals(2, y);
83 }
84 assertEquals('class f { }', f.toString());
85})();
86
87(function shadowingConstDoesntBind() {
88 const f = 1;
89 assertEquals(1, f);
90 {
91 let y = 3;
92 function f() {
93 y = 2;
94 }
95 f();
96 assertEquals(2, y);
97 }
98 assertEquals(1, f);
99})();
100
101(function shadowingVarBinds() {
102 var f = 1;
103 assertEquals(1, f);
104 {
105 let y = 3;
106 function f() {
107 y = 2;
108 }
109 f();
110 assertEquals(2, y);
111 }
112 assertEquals('function', typeof f);
113})();
114
115(function conditional() {
116 if (true) {
117 function f() { return 1; }
118 } else {
119 function f() { return 2; }
120 }
121 assertEquals(1, f());
122
123 if (false) {
124 function g() { return 1; }
125 } else {
126 function g() { return 2; }
127 }
128 assertEquals(2, g());
129})();
130
131(function skipExecution() {
132 {
133 function f() { return 1; }
134 }
135 assertEquals(1, f());
136 {
137 function f() { return 2; }
138 }
139 assertEquals(2, f());
140 L: {
141 assertEquals(3, f());
142 break L;
143 function f() { return 3; }
144 }
145 assertEquals(2, f());
146})();
147
148// Test that shadowing arguments is fine
149(function shadowArguments(x) {
150 assertArrayEquals([1], arguments);
151 {
152 assertEquals('function', typeof arguments);
153 function arguments() {}
154 assertEquals('function', typeof arguments);
155 }
156 assertEquals('function', typeof arguments);
157})(1);
158
159// Shadow function parameter
160(function shadowParameter(x) {
161 assertEquals(1, x);
162 {
163 function x() {}
164 }
165 assertEquals('function', typeof x);
166})(1);
167
168// Shadow function parameter
169(function shadowDefaultParameter(x = 0) {
170 assertEquals(1, x);
171 {
172 function x() {}
173 }
174 // TODO(littledan): Once destructured parameters are no longer
175 // let-bound, enable this assertion. This is the core of the test.
176 // assertEquals('function', typeof x);
177})(1);
178
179(function shadowRestParameter(...x) {
180 assertArrayEquals([1], x);
181 {
182 function x() {}
183 }
184 // TODO(littledan): Once destructured parameters are no longer
185 // let-bound, enable this assertion. This is the core of the test.
186 // assertEquals('function', typeof x);
187})(1);
188
189assertThrows(function notInDefaultScope(x = y) {
190 {
191 function y() {}
192 }
193 assertEquals('function', typeof y);
194 assertEquals(x, undefined);
195}, ReferenceError);
196
197// Test that hoisting from blocks does happen in global scope
198function globalHoisted() { return 0; }
199{
200 function globalHoisted() { return 1; }
201}
202assertEquals(1, globalHoisted());
203
204// Also happens when not previously defined
205assertEquals(undefined, globalUndefinedHoisted);
206{
207 function globalUndefinedHoisted() { return 1; }
208}
209assertEquals(1, globalUndefinedHoisted());
210var globalUndefinedHoistedDescriptor =
211 Object.getOwnPropertyDescriptor(this, "globalUndefinedHoisted");
212assertFalse(globalUndefinedHoistedDescriptor.configurable);
213assertTrue(globalUndefinedHoistedDescriptor.writable);
214assertTrue(globalUndefinedHoistedDescriptor.enumerable);
215assertEquals(1, globalUndefinedHoistedDescriptor.value());
216
217// When a function property is hoisted, it should be
218// made enumerable.
219// BUG(v8:4451)
220Object.defineProperty(this, "globalNonEnumerable", {
221 value: false,
222 configurable: true,
223 writable: true,
224 enumerable: false
225});
226eval("{function globalNonEnumerable() { return 1; }}");
227var globalNonEnumerableDescriptor
228 = Object.getOwnPropertyDescriptor(this, "globalNonEnumerable");
229// BUG(v8:4451): Should be made non-configurable
230assertTrue(globalNonEnumerableDescriptor.configurable);
231assertTrue(globalNonEnumerableDescriptor.writable);
232// BUG(v8:4451): Should be made enumerable
233assertFalse(globalNonEnumerableDescriptor.enumerable);
234assertEquals(1, globalNonEnumerableDescriptor.value());
235
236// When a function property is hoisted, it should be overwritten and
237// made writable and overwritten, even if the property was non-writable.
238Object.defineProperty(this, "globalNonWritable", {
239 value: false,
240 configurable: true,
241 writable: false,
242 enumerable: true
243});
244eval("{function globalNonWritable() { return 1; }}");
245var globalNonWritableDescriptor
246 = Object.getOwnPropertyDescriptor(this, "globalNonWritable");
247// BUG(v8:4451): Should be made non-configurable
248assertTrue(globalNonWritableDescriptor.configurable);
249// BUG(v8:4451): Should be made writable
250assertFalse(globalNonWritableDescriptor.writable);
251assertFalse(globalNonEnumerableDescriptor.enumerable);
252// BUG(v8:4451): Should be overwritten
253assertEquals(false, globalNonWritableDescriptor.value);
254
255// Test that hoisting from blocks does happen in an eval
256eval(`
257 function evalHoisted() { return 0; }
258 {
259 function evalHoisted() { return 1; }
260 }
261 assertEquals(1, evalHoisted());
262`);
263
264// Test that hoisting from blocks happens from eval in a function
265!function() {
266 eval(`
267 function evalInFunctionHoisted() { return 0; }
268 {
269 function evalInFunctionHoisted() { return 1; }
270 }
271 assertEquals(1, evalInFunctionHoisted());
272 `);
273}();
274
275let dontHoistGlobal;
276{ function dontHoistGlobal() {} }
277assertEquals(undefined, dontHoistGlobal);
278
279let dontHoistEval;
280// BUG(v8:) This shouldn't hoist and shouldn't throw
281var throws = false;
282try {
283 eval("{ function dontHoistEval() {} }");
284} catch (e) {
285 throws = true;
286}
287assertTrue(throws);
288
289// When the global object is frozen, silently don't hoist
290// Currently this actually throws BUG(v8:4452)
291Object.freeze(this);
292throws = false;
293try {
294 eval('{ function hoistWhenFrozen() {} }');
295} catch (e) {
296 throws = true;
297}
298assertFalse(this.hasOwnProperty("hoistWhenFrozen"));
299assertThrows(() => hoistWhenFrozen, ReferenceError);
300// Should be assertFalse BUG(v8:4452)
301assertTrue(throws);