OLD | NEW |
| (Empty) |
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: --harmony-sloppy --harmony-sloppy-let | |
6 // Flags: --harmony-sloppy-function | |
7 | |
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-decl
arations-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 | |
189 assertThrows(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 | |
198 function globalHoisted() { return 0; } | |
199 { | |
200 function globalHoisted() { return 1; } | |
201 } | |
202 assertEquals(1, globalHoisted()); | |
203 | |
204 // Also happens when not previously defined | |
205 assertEquals(undefined, globalUndefinedHoisted); | |
206 { | |
207 function globalUndefinedHoisted() { return 1; } | |
208 } | |
209 assertEquals(1, globalUndefinedHoisted()); | |
210 var globalUndefinedHoistedDescriptor = | |
211 Object.getOwnPropertyDescriptor(this, "globalUndefinedHoisted"); | |
212 assertFalse(globalUndefinedHoistedDescriptor.configurable); | |
213 assertTrue(globalUndefinedHoistedDescriptor.writable); | |
214 assertTrue(globalUndefinedHoistedDescriptor.enumerable); | |
215 assertEquals(1, globalUndefinedHoistedDescriptor.value()); | |
216 | |
217 // When a function property is hoisted, it should be | |
218 // made enumerable. | |
219 // BUG(v8:4451) | |
220 Object.defineProperty(this, "globalNonEnumerable", { | |
221 value: false, | |
222 configurable: true, | |
223 writable: true, | |
224 enumerable: false | |
225 }); | |
226 eval("{function globalNonEnumerable() { return 1; }}"); | |
227 var globalNonEnumerableDescriptor | |
228 = Object.getOwnPropertyDescriptor(this, "globalNonEnumerable"); | |
229 // BUG(v8:4451): Should be made non-configurable | |
230 assertTrue(globalNonEnumerableDescriptor.configurable); | |
231 assertTrue(globalNonEnumerableDescriptor.writable); | |
232 // BUG(v8:4451): Should be made enumerable | |
233 assertFalse(globalNonEnumerableDescriptor.enumerable); | |
234 assertEquals(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. | |
238 Object.defineProperty(this, "globalNonWritable", { | |
239 value: false, | |
240 configurable: true, | |
241 writable: false, | |
242 enumerable: true | |
243 }); | |
244 eval("{function globalNonWritable() { return 1; }}"); | |
245 var globalNonWritableDescriptor | |
246 = Object.getOwnPropertyDescriptor(this, "globalNonWritable"); | |
247 // BUG(v8:4451): Should be made non-configurable | |
248 assertTrue(globalNonWritableDescriptor.configurable); | |
249 // BUG(v8:4451): Should be made writable | |
250 assertFalse(globalNonWritableDescriptor.writable); | |
251 assertFalse(globalNonEnumerableDescriptor.enumerable); | |
252 // BUG(v8:4451): Should be overwritten | |
253 assertEquals(false, globalNonWritableDescriptor.value); | |
254 | |
255 // Test that hoisting from blocks does happen in an eval | |
256 eval(` | |
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 | |
275 let dontHoistGlobal; | |
276 { function dontHoistGlobal() {} } | |
277 assertEquals(undefined, dontHoistGlobal); | |
278 | |
279 let dontHoistEval; | |
280 // BUG(v8:) This shouldn't hoist and shouldn't throw | |
281 var throws = false; | |
282 try { | |
283 eval("{ function dontHoistEval() {} }"); | |
284 } catch (e) { | |
285 throws = true; | |
286 } | |
287 assertTrue(throws); | |
288 | |
289 // When the global object is frozen, silently don't hoist | |
290 // Currently this actually throws BUG(v8:4452) | |
291 Object.freeze(this); | |
292 throws = false; | |
293 try { | |
294 eval('{ function hoistWhenFrozen() {} }'); | |
295 } catch (e) { | |
296 throws = true; | |
297 } | |
298 assertFalse(this.hasOwnProperty("hoistWhenFrozen")); | |
299 assertThrows(() => hoistWhenFrozen, ReferenceError); | |
300 // Should be assertFalse BUG(v8:4452) | |
301 assertTrue(throws); | |
OLD | NEW |