blockscope-functionbinding.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. function print(x) { WScript.Echo(x); }
  6. print('\nTest 1: Simple case with single block-scoped function\n');
  7. (function ()
  8. {
  9. // with prior reference
  10. print(f);
  11. if (true)
  12. {
  13. function f() { }
  14. print(f);
  15. }
  16. print(f);
  17. // without prior reference
  18. if (true)
  19. {
  20. function g() { }
  21. print(g);
  22. }
  23. print(g);
  24. // without prior or in-block-scope reference
  25. if (true)
  26. {
  27. function h() { }
  28. }
  29. print(h);
  30. })();
  31. print('\nTest 2: Block-scoped function shadows outer let binding, but leaks into function scope\n');
  32. (function ()
  33. {
  34. print(f);
  35. if (true)
  36. {
  37. let f = 'let f';
  38. print(f);
  39. if (true)
  40. {
  41. function f() { }
  42. print(f);
  43. }
  44. print(f);
  45. }
  46. print(f);
  47. })();
  48. print('\nTest 3: Assignment to function in block behaves like assigning let variable; function still leaks out to function scope; assignment does not affect function scope binding\n');
  49. (function ()
  50. {
  51. print(f);
  52. if (true)
  53. {
  54. let f = 'let f';
  55. print(f);
  56. if (true)
  57. {
  58. function f() { }
  59. f = 'reassigned inner function declared "let" f';
  60. print(f);
  61. }
  62. print(f);
  63. f = 'reassigned outer let f';
  64. print(f);
  65. }
  66. print(f);
  67. })();
  68. print('\nTest 4: Last executed declaration wins; simple case\n');
  69. (function ()
  70. {
  71. if (true)
  72. {
  73. function f(one) { }
  74. print(f);
  75. }
  76. print(f);
  77. if (true)
  78. {
  79. function f(two) { }
  80. print(f);
  81. }
  82. print(f);
  83. })();
  84. print('\nTest 5: Inner shadows outer and last executed (inner) wins for function scope\n');
  85. (function ()
  86. {
  87. if (true)
  88. {
  89. function f(outer) { }
  90. print(f);
  91. if (true)
  92. {
  93. function f(inner) { }
  94. print(f);
  95. }
  96. print(f);
  97. }
  98. print(f);
  99. })();
  100. print('\nTest 6: Last declaration executed wins; loop and conditionals\n');
  101. (function ()
  102. {
  103. let x = 0;
  104. print(f);
  105. while (x < 3)
  106. {
  107. print(f);
  108. if (x === 0 || x === 2)
  109. {
  110. function f(one) { }
  111. print(f);
  112. }
  113. else if (x === 1)
  114. {
  115. function f(two) { }
  116. print(f);
  117. }
  118. print(f);
  119. x += 1;
  120. }
  121. print(f);
  122. })();
  123. print('\nTest 7: Make sure function scope binding is initialized even when it is an activation object (imposed by presence of eval)\n');
  124. (function ()
  125. {
  126. eval('print(f);');
  127. if (true)
  128. {
  129. function f() { }
  130. }
  131. eval('print(f);');
  132. print(f);
  133. })();
  134. print('\nTest 8: Function scope binding does not occur in strict mode\n');
  135. (function ()
  136. {
  137. for (var i = 0; i < 2; i += 1)
  138. {
  139. try
  140. {
  141. (function ()
  142. {
  143. "use strict";
  144. if (i == 0)
  145. print(f);
  146. if (true)
  147. {
  148. function f() { }
  149. print(f);
  150. }
  151. print(f);
  152. })();
  153. }
  154. catch (e)
  155. {
  156. print(e);
  157. }
  158. }
  159. })();
  160. print('\nTest 9: Overwriting user declared var\n');
  161. (function ()
  162. {
  163. var f = 'var f';
  164. print(f);
  165. if (true)
  166. {
  167. function f() { }
  168. print(f);
  169. }
  170. print(f);
  171. })();
  172. print('\nTest 10: inner functions before block scope function should bind to function scoped binding, not outer scope\n');
  173. (function ()
  174. {
  175. function f()
  176. {
  177. print('outer scope f()');
  178. }
  179. (function ()
  180. {
  181. function g ()
  182. {
  183. if (f === undefined)
  184. {
  185. print(f);
  186. }
  187. else
  188. {
  189. f();
  190. }
  191. }
  192. g();
  193. if (true)
  194. {
  195. function f ()
  196. {
  197. print('inner block-scope f()');
  198. }
  199. }
  200. g();
  201. })();
  202. })();
  203. print('\nTest 11: Function declarations shadow with object but also do not assign to with object properties\n');
  204. (function ()
  205. {
  206. print(f);
  207. print(g);
  208. with ({ f: 'with f', g: 'with g' })
  209. {
  210. function f() { }
  211. function h() { }
  212. print(f);
  213. if (true)
  214. {
  215. function g() { }
  216. print(g);
  217. }
  218. print(g);
  219. print(h);
  220. }
  221. print(f);
  222. print(g);
  223. print(h);
  224. })();
  225. print('\nTest 12: Ensure redeclaration errors do not occur with var binding of block scoped functions\n');
  226. (function ()
  227. {
  228. let f = 'let f';
  229. print(f);
  230. {
  231. function f() { }
  232. function g() { }
  233. print(f);
  234. print(g);
  235. }
  236. let g = 'let g';
  237. print(f);
  238. print(g);
  239. })();
  240. print('\nTest 13: Eval does not leak let and const bindings\n');
  241. (function ()
  242. {
  243. var f = 'var f';
  244. print(f);
  245. try { print(g); } catch (e) { print(e); }
  246. eval("var f = 'eval var f'; function g() { } let h = 'eval let h'; const i = 'eval const i'; if (true) { var j = 'eval blockscoped var j'; let k = 'eval blockscoped let k'; }");
  247. print(f);
  248. print(g);
  249. try { print(h); } catch (e) { print(e); }
  250. try { print(i); } catch (e) { print(e); }
  251. print(j);
  252. try { print(k); } catch (e) { print(e); }
  253. })();
  254. print('\nTest 14: Eval leaks vars, and var declarations bind to block scoped bindings for rhs initialization\n');
  255. (function ()
  256. {
  257. var f = 'var f';
  258. {
  259. let f = 'let f';
  260. eval("var f = 'eval var f'; var g = 'eval var g'; print(f); print(g);");
  261. print(f);
  262. print(g);
  263. }
  264. print(f);
  265. print(g);
  266. })();
  267. print('\nTest 15: Eval should have TDZ use before declaration error\n');
  268. (function ()
  269. {
  270. try
  271. {
  272. eval("f(); let x = 'let x'; function f() { print(x); }");
  273. }
  274. catch (e)
  275. {
  276. print(e);
  277. }
  278. })();
  279. print('\nTest 16: Eval function declarations create/assign to a var binding and assign to let binding, and create a let binding if not at eval global scope\n');
  280. (function ()
  281. {
  282. function f(notineval) { }
  283. if (true)
  284. {
  285. function g(notineval) { }
  286. function h(notineval) { }
  287. eval("function f(ineval) { }; function g(ineval) { }; if (true) { function h(ineval) { }; print(h); } print(h);");
  288. print(f); // this should be f(ineval)
  289. print(g); // this should be g(ineval)
  290. print(h); // this should be h(notineval)
  291. }
  292. print(f); // this should be f(ineval)
  293. print(g); // this should be g(ineval)
  294. print(h); // this should be h(ineval)
  295. })();
  296. print('\nTest 17: var initializations should find block scoped lets but still create properties at function scope\n');
  297. (function ()
  298. {
  299. var f = 'var f not in eval';
  300. if (true)
  301. {
  302. let g = 'let g not in eval';
  303. eval("var f = 'var f in eval'; if (true) { var g = 'var g in eval'; }");
  304. print(f); // this should be 'var f in eval'
  305. print(g); // this should be 'let g in eval'
  306. }
  307. print(f); // this should be 'var f in eval'
  308. print(g); // this should be 'undefined'
  309. })();
  310. print('\nTest 18: function declaration in eval should shadow variables declared outside eval (strict)\n');
  311. (function ()
  312. {
  313. // Only strict mode has this behavior
  314. "use strict";
  315. var f = 'var f';
  316. if (true)
  317. {
  318. let g = 'let g';
  319. eval("function f() { } function g() { } f(); g(); print(f); print(g);");
  320. print(g);
  321. }
  322. print(f);
  323. try
  324. {
  325. print(g);
  326. }
  327. catch (e)
  328. {
  329. print(e);
  330. }
  331. })();
  332. print('\nTest 19: function declaration var binding should be ignored when same named let/const variable is at function scope\n');
  333. (function ()
  334. {
  335. // Note: declared var's simply get overwritten instead of introducing shadowing
  336. // static
  337. (function () {
  338. let f = 'let f';
  339. {
  340. function f() { }
  341. print(f);
  342. }
  343. print(f);
  344. })();
  345. (function () {
  346. const g = 'const g';
  347. {
  348. function g() { }
  349. print(g);
  350. }
  351. print(g);
  352. })();
  353. (function () {
  354. var h = 'var h';
  355. {
  356. function h() { }
  357. print(h);
  358. }
  359. print(h);
  360. })();
  361. (function () {
  362. {
  363. function i() { }
  364. print(i);
  365. }
  366. let i = 'let i';
  367. print(i);
  368. })();
  369. (function () {
  370. {
  371. function j() { }
  372. print(j);
  373. }
  374. const j = 'const j';
  375. print(j);
  376. })();
  377. (function () {
  378. {
  379. function k() { }
  380. print(k);
  381. }
  382. var k = 'var k';
  383. print(k);
  384. })();
  385. // dynamic via eval
  386. (function () {
  387. let l = 'let l';
  388. {
  389. try { eval("function l(one) { }; print(l);"); } catch (e) { print(e); }
  390. print(l);
  391. }
  392. print(l);
  393. l = 'outer let l';
  394. {
  395. let l = 'inner let l';
  396. try { eval("function l(two) { }; print(l);"); } catch (e) { print(e); }
  397. print(l);
  398. }
  399. print(l);
  400. })();
  401. (function () {
  402. const m = 'const m';
  403. {
  404. try { eval("function m(one) { }; print(m);"); } catch (e) { print(e); }
  405. print(m);
  406. }
  407. print(m);
  408. {
  409. const m = 'inner const m';
  410. try { eval("function m(two) { }; print(m);"); } catch (e) { print(e); }
  411. print(m);
  412. }
  413. print(m);
  414. {
  415. let m = 'inner let m';
  416. try { eval("function m(three) { }; print(m);"); } catch (e) { print(e); }
  417. print(m);
  418. }
  419. print(m);
  420. })();
  421. (function () {
  422. var n = 'var n';
  423. {
  424. eval("function n() { }; print(n);");
  425. print(n);
  426. }
  427. print(n);
  428. })();
  429. (function () {
  430. {
  431. try { eval("function o() { }; print(o);"); } catch (e) { print(e); }
  432. }
  433. let o = 'let o';
  434. print(o);
  435. })();
  436. (function () {
  437. {
  438. try { eval("function p() { }; print(p);"); } catch (e) { print(e); }
  439. }
  440. const p = 'const p';
  441. print(p);
  442. })();
  443. (function () {
  444. {
  445. try { eval("function q() { }; print(q);"); } catch (e) { print(e); }
  446. }
  447. var q = 'var q';
  448. print(q);
  449. })();
  450. // function var binding should cause scope slot indices to be messed up;
  451. // see bug 513299.
  452. function test1() {
  453. eval('');
  454. a;
  455. {
  456. function b() { }
  457. }
  458. const b = 1;
  459. var a;
  460. }
  461. test1();
  462. })();
  463. print('\nTest 20: Function declaration in statement context without {}\n');
  464. (function() {
  465. if (1)
  466. function f1() { print('1'); }
  467. else
  468. function f1() { print('0'); }
  469. if (0)
  470. function f2() { print('1'); }
  471. else
  472. function f2() { print('0'); }
  473. if (1) {
  474. if (1)
  475. function f3() { print('1'); }
  476. else
  477. function f3() { print('0'); }
  478. if (0)
  479. function f4() { print('1'); }
  480. else
  481. function f4() { print('0'); }
  482. }
  483. while (false)
  484. function f5() {}
  485. for (;false;)
  486. function f6() {}
  487. for (var p in {a:'a'})
  488. function f7() {}
  489. for (var e of [1])
  490. function f8() {}
  491. with ({})
  492. function f9() {}
  493. f1();
  494. f2();
  495. f3();
  496. f4();
  497. f7();
  498. f8();
  499. f9();
  500. })();
  501. print('\nTest 21: Function declaration in statement context without {}, strict mode\n');
  502. (function() {
  503. "use strict";
  504. // The B.3.4 exceptions are not allowed in strict mode
  505. try {
  506. eval('if (true)' +
  507. ' function f() { return "not allowed in strict mode"; }' +
  508. 'else' +
  509. ' void 0;');
  510. }
  511. catch(ex) {
  512. print('21.1: ' + ex.message);
  513. }
  514. try {
  515. eval('if (true)' +
  516. ' void 0;' +
  517. 'else' +
  518. ' function f() { return "not allowed in strict mode"; }');
  519. }
  520. catch(ex) {
  521. print('21.2: ' + ex.message);
  522. }
  523. try {
  524. eval('if (true)' +
  525. ' function f() { return "not allowed in strict mode"; }' +
  526. 'else' +
  527. ' function f() { return "not allowed in strict mode"; }');
  528. }
  529. catch(ex) {
  530. print('21.3: ' + ex.message);
  531. }
  532. try {
  533. eval('if (true)' +
  534. ' function f() { return "not allowed in strict mode"; }');
  535. }
  536. catch(ex) {
  537. print('21.4: ' + ex.message);
  538. }
  539. })();
  540. print('\nTest 22: Function declaration in statement context without {}, illegal in sloppy mode\n');
  541. (function() {
  542. // Always illegal syntax regardless of strict mode
  543. // generator functions are GeneratorFunctionDeclaration, not FunctionDeclaration
  544. // so are also not allowed by the B.3.4 exception
  545. try {
  546. eval('if (true)' +
  547. ' function* f() { return "never allowed"; }' +
  548. 'else' +
  549. ' void 0;');
  550. }
  551. catch(ex) {
  552. print('22.1: ' + ex.message);
  553. }
  554. try {
  555. eval('if (true)' +
  556. ' void 0;' +
  557. 'else' +
  558. ' function* f() { return "never allowed"; }');
  559. }
  560. catch(ex) {
  561. print('22.2: ' + ex.message);
  562. }
  563. try {
  564. eval('if (true)' +
  565. ' function* f() { return "never allowed"; }' +
  566. 'else' +
  567. ' function* f() { return "never allowed"; }');
  568. }
  569. catch(ex) {
  570. print('22.3: ' + ex.message);
  571. }
  572. try {
  573. eval('if (true)' +
  574. ' function* f() { return "never allowed"; }');
  575. }
  576. catch(ex) {
  577. print('22.4: ' + ex.message);
  578. }
  579. // async is ES7 but presumably will also not be FunctionDeclaration in the grammar
  580. // and so are also not allowed by the B.3.4 exception
  581. try {
  582. eval('if (true)' +
  583. ' async function f() { return "never allowed"; }' +
  584. 'else' +
  585. ' void 0;');
  586. }
  587. catch(ex) {
  588. print('22.5: ' + ex.message);
  589. }
  590. try {
  591. eval('if (true)' +
  592. ' void 0;' +
  593. 'else' +
  594. ' async function f() { return "never allowed"; }');
  595. }
  596. catch(ex) {
  597. print('22.6: ' + ex.message);
  598. }
  599. try {
  600. eval('if (true)' +
  601. ' async function f() { return "never allowed"; }' +
  602. 'else' +
  603. ' async function f() { return "never allowed"; }');
  604. }
  605. catch(ex) {
  606. print('22.7: ' + ex.message);
  607. }
  608. try {
  609. eval('if (true)' +
  610. ' async function f() { return "never allowed"; }' +
  611. 'else' +
  612. ' async function f() { return "never allowed"; }');
  613. }
  614. catch(ex) {
  615. print('22.8: ' + ex.message);
  616. }
  617. try {
  618. eval('if (true)' +
  619. ' async function f() { return "never allowed"; }');
  620. }
  621. catch(ex) {
  622. print('22.8: ' + ex.message);
  623. }
  624. })();
  625. // Leave this test last since it is at global scope and would be awkward to place in the middle of the cleanly contained tests
  626. // above, and also so that it does not accidentally influence the previous tests.
  627. print('\nTest Global: Global scope has the same semantics for block-scoped function declarations\n');
  628. print(glo_f);
  629. if (true)
  630. {
  631. function glo_f() { }
  632. print(glo_f);
  633. }
  634. print(glo_f);
  635. function glo_g(globalscope) { }
  636. print(glo_g);
  637. if (true)
  638. {
  639. function glo_g(blockscope) { }
  640. print(glo_g);
  641. }
  642. print(glo_g);
  643. print(glo_h);
  644. if (true)
  645. {
  646. function glo_h(one) { }
  647. print(glo_h);
  648. }
  649. print(glo_h);
  650. if (true)
  651. {
  652. function glo_h(two) { }
  653. print(glo_h);
  654. }
  655. print(glo_h);
  656. print('\nGlobal version of Test 19: function declaration\'s var binding should be ignored when same named let/const variable is at global scope\n');
  657. // Note: declared var's simply get overwritten instead of introducing shadowing
  658. // static
  659. let glo_t19_f = 'let glo_t19_f';
  660. {
  661. function glo_t19_f() { }
  662. print(glo_t19_f);
  663. }
  664. print(glo_t19_f);
  665. const glo_t19_g = 'const glo_t19_g';
  666. {
  667. function glo_t19_g() { }
  668. print(glo_t19_g);
  669. }
  670. print(glo_t19_g);
  671. var glo_t19_h = 'var glo_t19_h';
  672. {
  673. function glo_t19_h() { }
  674. print(glo_t19_h);
  675. }
  676. print(glo_t19_h);
  677. {
  678. function glo_t19_i() { }
  679. print(glo_t19_i);
  680. }
  681. let glo_t19_i = 'let glo_t19_i';
  682. print(glo_t19_i);
  683. {
  684. function glo_t19_j() { }
  685. print(glo_t19_j);
  686. }
  687. const glo_t19_j = 'const glo_t19_j';
  688. print(glo_t19_j);
  689. {
  690. function glo_t19_k() { }
  691. print(glo_t19_k);
  692. }
  693. var glo_t19_k = 'var glo_t19_k';
  694. print(glo_t19_k);
  695. // dynamic via eval
  696. let glo_t19_l = 'let glo_t19_l';
  697. {
  698. try { eval("function glo_t19_l(one) { }; print(glo_t19_l);"); } catch (e) { print(e); }
  699. print(glo_t19_l);
  700. }
  701. print(glo_t19_l);
  702. print(this.glo_t19_l);
  703. {
  704. try { eval("function declaredLater(one) { }; print(declaredLater);"); } catch (e) { print(e); }
  705. }
  706. let declaredLater = 'let declaredLater';
  707. print(declaredLater);
  708. glo_t19_l = 'outer let glo_t19_l';
  709. {
  710. let glo_t19_l = 'inner let glo_t19_l';
  711. try { eval("function glo_t19_l(two) { }; print(glo_t19_l);"); } catch (e) { print(e); }
  712. print(glo_t19_l);
  713. }
  714. print(glo_t19_l);
  715. print(this.glo_t19_l);
  716. const glo_t19_m = 'const glo_t19_m';
  717. {
  718. try { eval("function glo_t19_m(one) { }; print(glo_t19_m);"); } catch (e) { print(e); }
  719. print(glo_t19_m);
  720. }
  721. print(glo_t19_m);
  722. print(this.glo_t19_m);
  723. {
  724. const glo_t19_m = 'inner const m';
  725. try { eval("function glo_t19_m(two) { }; print(glo_t19_m);"); } catch (e) { print(e); }
  726. print(glo_t19_m);
  727. }
  728. print(glo_t19_m);
  729. print(this.glo_t19_m);
  730. {
  731. let glo_t19_m = 'inner let m';
  732. try { eval("function glo_t19_m(three) { }; print(glo_t19_m);"); } catch (e) { print(e); }
  733. print(glo_t19_m);
  734. }
  735. print(glo_t19_m);
  736. print(this.glo_t19_m);
  737. var glo_t19_n = 'var glo_t19_n';
  738. {
  739. eval("function glo_t19_n() { }; print(glo_t19_n);");
  740. print(glo_t19_n);
  741. }
  742. print(glo_t19_n);
  743. {
  744. try { eval("function glo_t19_o() { }; print(glo_t19_o);"); } catch (e) { print(e); }
  745. }
  746. let glo_t19_o = 'let glo_t19_o';
  747. print(glo_t19_o);
  748. {
  749. try { eval("function glo_t19_p() { }; print(glo_t19_p);"); } catch (e) { print(e); }
  750. }
  751. const glo_t19_p = 'const glo_t19_p';
  752. print(glo_t19_p);
  753. {
  754. try { eval("function glo_t19_q() { }; print(glo_t19_q);"); } catch (e) { print(e); }
  755. }
  756. var glo_t19_q = 'var glo_t19_q';
  757. print(glo_t19_q);
  758. {
  759. function xxx(){}
  760. }
  761. try
  762. {
  763. eval('xxx()++');
  764. }
  765. catch(e)
  766. {
  767. print(e);
  768. }
  769. (function () {
  770. for (var ngjkfy = 0; ngjkfy < 16; ++ngjkfy) {
  771. if (ngjkfy % 5 == 2) {
  772. function y() {
  773. }
  774. } else {
  775. for (qvjjmr = 0; qvjjmr < 4; ++qvjjmr) {
  776. 'u{7cb6}';
  777. }
  778. }
  779. }
  780. var y = 0;
  781. }());