destructuring_bugs.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  6. var tests = [
  7. {
  8. name: "Destructuring bug fixes validation",
  9. body: function () {
  10. assert.throws(function () { eval("function f1() { var a = 10; [a+2] = []; }; f1();"); }, SyntaxError, "var empty object declaration pattern without an initializer is not valid syntax", "Unexpected operator in destructuring expression");
  11. assert.throws(function () { eval("function f2() { var a = 10; ({x:a+2} = {x:2}); }; f2();"); }, SyntaxError, "var empty object declaration pattern without an initializer is not valid syntax", "Unexpected operator in destructuring expression");
  12. assert.throws(function () { eval("function f3() { var a = 10; for ([a+2] in []) { } }; f3();"); }, SyntaxError, "var empty object declaration pattern without an initializer is not valid syntax", "Unexpected operator in destructuring expression");
  13. assert.doesNotThrow(function () { eval("(function () { var x; for ({x:x}.x of [1,2]) {}; })();"); }, "for..of initializer start with left curly but not a pattern is valid syntax");
  14. assert.throws(function () { eval("(function () { 'use strict'; [x] = [1]; let x = 2; })();"); }, ReferenceError, "A variable, defined in pattern, is used before its declaration in not valid syntax", "Use before declaration");
  15. assert.throws(function () { eval("(function () { 'use strict'; let x1 = 1; ({x:x1, y:{y1:y1}} = {x:11, y:{y1:22}}); let y1 = 2; })();"); }, ReferenceError, "A variable, defined in nested pattern, is used before its declaration is not valid syntax", "Use before declaration");
  16. assert.throws(function () { eval("(function () { 'use strict'; [eval] = []; })();"); }, SyntaxError, "variable name 'eval' defined in array pattern is not valid in strict mode", "Invalid usage of 'eval' in strict mode");
  17. assert.throws(function () { eval("let a = [a] = [10]"); }, ReferenceError, "A let variable is used in the array pattern in the same statement where it is declared", "Use before declaration");
  18. assert.throws(function () { eval("let a = {a:a} = {}"); }, ReferenceError, "A let variable is used in object pattern in the same statement where it is declared", "Use before declaration");
  19. assert.throws(function () { eval("var a = 1; (delete [a] = [2]);"); }, SyntaxError, "Array literal in unary expression should not be converted to array pattern", "Invalid left-hand side in assignment.");
  20. assert.throws(function () { eval("var x, b; for ([x] = [((b) = 1)] of ' ') { }"); }, ReferenceError, "Initializer in for..in is not valid but no assert should be thrown", "Invalid left-hand side in assignment");
  21. assert.throws(function () { eval("for (let []; ;) { }"); }, SyntaxError, "Native for loop's head has one destructuring pattern without initializer", "Destructuring declarations must have an initializer");
  22. assert.throws(function () { eval("for (let a = 1, []; ;) { }"); }, SyntaxError, "Native for loop's head has second param as destructuring pattern without initializer", "Destructuring declarations must have an initializer");
  23. assert.throws(function () { eval("for (let [] = [], a = 1, {}; ;) { }"); }, SyntaxError, "Native for loop's head has third param as object destructuring pattern without initializer", "Destructuring declarations must have an initializer");
  24. assert.throws(function () { eval("for (let [[a] = []]; ;) { }"); }, SyntaxError, "Native for loop's head as destructuring pattern without initializer", "Destructuring declarations must have an initializer");
  25. assert.doesNotThrow(function () { eval("for ([]; ;) { break; }"); }, "Native for loop's head is an expression without initializer is valid syntax");
  26. assert.doesNotThrow(function () { eval("try { y; } catch({}) { }"); }, "Catching exception to empty pattern should not assert and is a valid syntax");
  27. assert.doesNotThrow(function () { eval("for({} = function (...a) { } in '' ) { }"); }, "Having a function with rest parameter as initializer should not assert and is a valid syntax");
  28. assert.doesNotThrow(function () { eval("for([] = ((...a) => {}) in '' ) { }"); }, "Having a lambda function with rest parameter as initializer should not assert and is a valid syntax");
  29. assert.doesNotThrow(function () { eval("[[[] = [function () { }] ] = []]"); }, "Nested array has array pattern which has function expression is a valid syntax");
  30. assert.doesNotThrow(function () { eval("var a = ({x = 1}) => x;"); }, "Lambda has Object destructuring as parameter which has initializer on shorthand is a valid syntax");
  31. assert.doesNotThrow(function () { eval("var a = (b, {x = 1}) => x;"); }, "Lambda has Object destructuring as a second parameter which has initializer on shorthand is a valid syntax");
  32. assert.doesNotThrow(function () { eval("var a = ({x = 1}, b) => x;"); }, "Lambda has Object destructuring as first parameter which has initializer on shorthand is a valid syntax");
  33. assert.throws(function () { eval("let a = ({name = 'foo'}, 1) = {}"); }, ReferenceError, "Object shorthand will behave as pattern when on left-hand side and should not throw syntax error");
  34. }
  35. },
  36. {
  37. name: "Destructuring bug fix - function expression under destructuring pattern does not crash",
  38. body: function () {
  39. var a = [];
  40. var b = 2;
  41. function f() {
  42. [ a [ function () { }, b ] ] = [2] ;
  43. }
  44. f();
  45. }
  46. },
  47. {
  48. name: "Destructuring bug fix - rest operator in for loop",
  49. body: function () {
  50. assert.throws(function () { eval("for (var {a: ...a1} = {}; ; ) { } "); }, SyntaxError, "Native for loop - usage of '...' in object destructuring pattern in not valid", "Unexpected ... operator");
  51. assert.throws(function () { eval("for (var {a: ...[]} = {}; ; ) { } "); }, SyntaxError, "Native for loop - usage of '...' before an array in object destructuring pattern in not valid", "Unexpected ... operator");
  52. assert.throws(function () { eval("for (var {a: ...[]} of '' ) { } "); }, SyntaxError, "for.of loop - usage of '...' before an array in object destructuring pattern in not valid", "Unexpected ... operator");
  53. }
  54. },
  55. {
  56. name: "Destructuring bug fix - call expression instead of reference node",
  57. body: function () {
  58. assert.throws(function () { eval("for (var a of {b: foo()} = {}) { }"); }, SyntaxError, "for.of loop has destructuring pattern which has call expression instead of a reference node", "Invalid destructuring assignment target");
  59. assert.throws(function () { eval("for ([{b: foo()} = {}] of {}) { }"); }, SyntaxError, "for.of loop has destructuring pattern on head which has call expression instead of a reference node", "Invalid destructuring assignment target");
  60. function foo() {
  61. return { bar : function() {} };
  62. }
  63. assert.throws(function () { eval("for (var a in {b: foo().bar()} = {}) { }"); }, SyntaxError, "for.in loop has destructuring pattern which has linked call expression instead of a reference node", "Invalid destructuring assignment target");
  64. assert.doesNotThrow(function () { eval("for (var a in {b: foo().bar} = {}) { }"); }, "for.in loop has destructuring pattern which has a reference node is valid syntax", );
  65. }
  66. },
  67. {
  68. name: "Destructuring bug fix - object coercible",
  69. body: function () {
  70. assert.throws(function () { eval("var {} = undefined"); }, TypeError, "Object declaration - RHS cannot be be undefined", "Cannot convert null or undefined to object");
  71. assert.throws(function () { eval("var {} = null"); }, TypeError, "Object declaration - RHS cannot be be null", "Cannot convert null or undefined to object");
  72. assert.throws(function () { eval("({} = undefined);"); }, TypeError, "Object assignment pattern - RHS cannot be be undefined", "Cannot convert null or undefined to object");
  73. assert.throws(function () { eval("([{}] = []);"); }, TypeError, "Object assignment pattern nested with array pattern has evaluated to have undefined as RHS", "Cannot convert null or undefined to object");
  74. assert.throws(function () { eval("function f({}){}; f();"); }, TypeError, "Object pattern on function - evaluated to have undefined from assignment expression", "Cannot convert null or undefined to object");
  75. assert.throws(function () { eval("function f({}){}; f(null);"); }, TypeError, "Object pattern on function - evaluated to have null from assignment expression", "Cannot convert null or undefined to object");
  76. }
  77. },
  78. {
  79. name: "Destructuring bug fix - a variable in body has the same name as param should not throw in the defer parse mode",
  80. body: function () {
  81. assert.doesNotThrow(function () { eval("function foo() { function bar([a]) { var a = 1; } }"); }, "variable 'a' is not a re-declaration" );
  82. assert.doesNotThrow(function () { eval("function foo() { function bar([a], {b, b1}, [c]) { var b1 = 1; } }"); }, "variable 'b1' is not a re-declaration" );
  83. assert.doesNotThrow(function () { eval("function foo() { ({c}) => { var c = 1; } }"); }, "variable 'c' is not a re-declaration" );
  84. }
  85. },
  86. {
  87. name: "Destructuring bug fix - assign to const",
  88. body: function () {
  89. assert.throws(function () { const c = 10; ({c} = {c:11}); }, TypeError, "Cannot assign to const", "Assignment to const");
  90. assert.throws(function () { eval("const c = 10; ({c} = {c:11});"); }, TypeError, "Cannot assign to const in eval", "Assignment to const");
  91. assert.throws(function () { const c = 10; eval("({c} = {c:11});"); }, TypeError, "Cannot assign to const in eval, where const is defined outsdie of eval", "Assignment to const");
  92. }
  93. },
  94. {
  95. name: "Destructuring bug fix - pattern with rest parameter",
  96. body: function () {
  97. assert.doesNotThrow(function () { eval("function foo({a}, ...b) { if (b) { } }; foo({});"); } );
  98. assert.doesNotThrow(function () { eval("function foo([], ...b) { if (b) { } }; foo([]);"); });
  99. }
  100. },
  101. {
  102. name: "Object Destructuring with empty identifier/reference",
  103. body: function () {
  104. assert.throws(function () { eval("var {x : } = {};"); }, SyntaxError);
  105. assert.throws(function () { eval("var {x : , } = {};"); }, SyntaxError);
  106. assert.throws(function () { eval("var {x : , y} = {};"); }, SyntaxError);
  107. assert.throws(function () { eval("({x : , y} = {});"); }, SyntaxError);
  108. }
  109. },
  110. {
  111. name: "Destructuring pattern at param has arguments as declaration",
  112. body: function () {
  113. assert.doesNotThrow(function () { eval("function foo([arguments]) { arguments; }; foo([1]);"); });
  114. assert.doesNotThrow(function () { eval("function foo({arguments}) { arguments; }; foo({arguments:1});"); });
  115. assert.doesNotThrow(function () { eval("function foo({x:{arguments}}) { arguments; }; foo({x:{arguments:1}});"); });
  116. }
  117. },
  118. {
  119. name: "Destructuring pattern at param has function as default value",
  120. body: function () {
  121. assert.doesNotThrow(function () { eval("function foo(x = ({y = function (p) {}} = 'bar')) {}; foo();"); });
  122. assert.doesNotThrow(function () { eval("var foo = (x = ({y = function (p) {}} = 'bar')) => {}; foo();"); });
  123. }
  124. },
  125. {
  126. name: "Destructuring empty patterns at param with arguments/eval at function body",
  127. body: function () {
  128. (function ({}, {}, {}, {}, {}, a) {
  129. eval("");
  130. assert.areEqual(arguments[1].x, 1);
  131. assert.areEqual(a, 2);
  132. })({}, {x:1}, {}, {}, {}, 2);
  133. (function ({}, {}, {}, {}, {}, a) {
  134. (function () {
  135. eval("");
  136. })();
  137. assert.areEqual(arguments[1].x, 1);
  138. assert.areEqual(a, 2);
  139. })({}, {x:1}, {}, {}, {}, 2);
  140. (function ({}, {}, {}, {}, {}, a) {
  141. (function () {
  142. a;
  143. })();
  144. eval("");
  145. assert.areEqual(arguments[1].x, 1);
  146. assert.areEqual(a, 2);
  147. })({}, {x:1}, {}, {}, {}, 2);
  148. }
  149. },
  150. {
  151. name: "Destructuring patterns (multiple identifiers in the pattern) at param with arguments/eval at function body",
  152. body: function () {
  153. (function (x1, {x2, x3}, [x4, x5], x6) {
  154. eval("");
  155. assert.areEqual(arguments[2], [4, 5]);
  156. })(1, {x2:2, x3:3}, [4, 5], 6);
  157. (function (x1, {x2, x3}, [x4, x5], x6) {
  158. var k = x1 + x2 + x3 + x4 + x5 + x6;
  159. eval("");
  160. assert.areEqual(arguments[2], [4, 5]);
  161. assert.areEqual(k, 21);
  162. })(1, {x2:2, x3:3}, [4, 5], 6);
  163. (function (x1, {x2, x3}, [x4, x5], x6) {
  164. (function() {
  165. eval("");
  166. });
  167. assert.areEqual(arguments[3], 6);
  168. var k = x1 + x2 + x3 + x4 + x5 + x6;
  169. assert.areEqual(k, 21);
  170. })(1, {x2:2, x3:3}, [4, 5], 6);
  171. (function (x1, {x2, x3}, [x4, x5], x6) {
  172. (function() {
  173. x3; x5; x6;
  174. })();
  175. var k = x1 + x2 + x3 + x4 + x5 + x6;
  176. assert.areEqual(k, 21);
  177. })(1, {x2:2, x3:3}, [4, 5], 6);
  178. (function (x1, {x2, x3}, [x4, x5], x6) {
  179. (function() {
  180. x3; x5; x6;
  181. })();
  182. var k = x1 + x2 + x3 + x4 + x5 + x6;
  183. assert.areEqual(arguments[3], 6);
  184. assert.areEqual(k, 21);
  185. })(1, {x2:2, x3:3}, [4, 5], 6);
  186. (function (x1, {x2, x3}, [x4, x5], x6) {
  187. (function() {
  188. assert.areEqual(x1 + x2 + x3 + x4 + x5 + x6, 21);
  189. })();
  190. })(1, {x2:2, x3:3}, [4, 5], 6);
  191. }
  192. },
  193. {
  194. name: "Destructuring patterns (multiple identifiers in the pattern) at param with lambdas, arguments and eval at function body",
  195. body: function () {
  196. (function (x1, {x2, x3}, [x4, x5], x6) {
  197. (() => {
  198. assert.areEqual(arguments[2], [4, 5]);
  199. })();
  200. eval("");
  201. })(1, {x2:2, x3:3}, [4, 5], 6);
  202. (function (x1, {x2, x3}, [x4, x5], x6) {
  203. (() => {
  204. var k = x1 + x2 + x3 + x4 + x5 + x6;
  205. eval("");
  206. assert.areEqual(arguments[2], [4, 5]);
  207. assert.areEqual(k, 21);
  208. })();
  209. })(1, {x2:2, x3:3}, [4, 5], 6);
  210. }
  211. },
  212. {
  213. name: "Destructuring patterns with rest at param with arguments/eval at function body",
  214. body: function () {
  215. (function (a, {b}, ...rest) {
  216. eval("");
  217. assert.areEqual(b, 2);
  218. assert.areEqual(arguments[2], 3);
  219. })(1, {b:2}, 3);
  220. (function (a, {b}, ...rest) {
  221. (function () {
  222. eval("");
  223. })();
  224. assert.areEqual(rest, [3]);
  225. assert.areEqual(arguments[2], 3);
  226. })(1, {b:2}, 3);
  227. (function (a, {b}, ...rest) {
  228. (function () {
  229. assert.areEqual(b, 2);
  230. assert.areEqual(rest, [3]);
  231. })();
  232. assert.areEqual(rest, [3]);
  233. assert.areEqual(arguments[2], 3);
  234. })(1, {b:2}, 3);
  235. }
  236. },
  237. {
  238. name: "Rest as pattern at param with arguments/eval at function body",
  239. body: function () {
  240. (function ([a, b], c, ...{'0': rest1, '1': rest2}) {
  241. eval("");
  242. assert.areEqual(rest1, 4);
  243. assert.areEqual(rest2, 5);
  244. assert.areEqual(c, 3);
  245. assert.areEqual(arguments[1], 3);
  246. })([1, 2], 3, 4, 5);
  247. (function ([a, b], c, ...{'0': rest1, '1': rest2}) {
  248. (function () {
  249. assert.areEqual(rest1, 4);
  250. assert.areEqual(rest2, 5);
  251. assert.areEqual(a+b, 3);
  252. })();
  253. eval("");
  254. assert.areEqual(arguments[0], [1, 2]);
  255. })([1, 2], 3, 4, 5);
  256. }
  257. },
  258. {
  259. name: "Accessing arguments at the params",
  260. body: function () {
  261. (function (x1, {x2, x3}, [x4, x5], x6 = arguments[0]) {
  262. eval("");
  263. assert.areEqual(arguments[2], [4, 5]);
  264. assert.areEqual(x6, 1);
  265. })(1, {x2:2, x3:3}, [4, 5], undefined);
  266. (function (x1, {x2, x3}, [x4, x5], x6 = arguments[0] = 11) {
  267. eval("");
  268. assert.areEqual(arguments[0], 11);
  269. assert.areEqual(x6, 11);
  270. })(1, {x2:2, x3:3}, [4, 5], undefined);
  271. }
  272. },
  273. {
  274. name: "Object destructuring - changing the RHS when emitting",
  275. body: function () {
  276. var a = {}, b;
  277. ({x:a, y:b = 1} = a);
  278. assert.areEqual(a, undefined);
  279. assert.areEqual(b, 1);
  280. }
  281. },
  282. {
  283. name: "Destructuring - Empty object pattern inside call node is a valid syntax",
  284. body: function () {
  285. function f() {
  286. ({} = []).Symbol.interator();
  287. eval("");
  288. };
  289. }
  290. },
  291. {
  292. name: "Destructuring - Place holder slots for pattern are accounted when undeferred.",
  293. body: function () {
  294. function foo({a}) {
  295. function x() {}
  296. eval('');
  297. }
  298. foo({});
  299. function foo1(...[b]) {
  300. function x() {}
  301. eval('');
  302. }
  303. foo1([]);
  304. }
  305. },
  306. {
  307. name: "Destructuring - array pattern at call expression (which causes iterator close)",
  308. body: function () {
  309. function foo(x1, x2, x3, x4) {
  310. assert.areEqual(x1, 'first');
  311. assert.areEqual(x2, 'second');
  312. assert.areEqual(x3[0][0], 'third');
  313. assert.areEqual(x4[0][0][0][0], 'fourth');
  314. }
  315. var a1;
  316. var a2;
  317. foo([{}] = 'first', 'second', [[a1]] = [['third']], [[[[a2]]]] = [[[['fourth']]]]);
  318. assert.areEqual(a1, 'third');
  319. assert.areEqual(a2, 'fourth');
  320. }
  321. },
  322. {
  323. name: "Destructuring - array patten at call expression - validating the next/return functions are called.",
  324. body: function () {
  325. var nextCount = 0;
  326. var returnCount = 0;
  327. var iterable = {};
  328. iterable[Symbol.iterator] = function () {
  329. return {
  330. next: function() {
  331. nextCount++;
  332. return {value : 1, done:false};
  333. },
  334. return: function (value) {
  335. returnCount++;
  336. return {done:true};
  337. }
  338. };
  339. };
  340. var obj = {
  341. set prop(val) {
  342. throw new Error('From setter');
  343. }
  344. };
  345. var foo = function () { };
  346. assert.throws(function () { foo([[obj.prop]] = [iterable]); }, Error, 'pattern at call expression throws and return function is called', 'From setter');
  347. assert.areEqual(nextCount, 1);
  348. assert.areEqual(returnCount, 1);
  349. }
  350. },
  351. {
  352. name: "Destructuring pattern at param has nested blocks.",
  353. body: function () {
  354. assert.doesNotThrow(function () { eval("var e = 1; ( {mnopqrs = ((( {} = (1))))} = (e)) => { try{ } catch(e) {}}") }, "Should not throw when the default value initializer has extra parentheses.");
  355. assert.doesNotThrow(function () { eval("var e = 1; ( {tuvwxy = ((( {} = 1 )))} = (e)) => { try{ } catch(e) {}}") }, "Should not throw when the default value and initializer are wrapped in extra parentheses.");
  356. assert.doesNotThrow(function () { eval("var e = 1; ( {abcdef = (((((foo)) = (1))))} = (e)) => { try{ } catch(e) {}}") }, "Should not throw when the default value and it's initializer both have extra parentheses.");
  357. assert.doesNotThrow(function () { eval("var e = 1; ( {ghijkl = (((((foo)) = 1 )))} = (e)) => { try{ } catch(e) {}}") }, "Should not throw when the default value has extra parentheses.");
  358. assert.doesNotThrow(function () { eval("var e = 1; ( {mnopqrs = ((( foo = (1))))} = (e)) => { try{ } catch(e) {}}") }, "Should not throw when the default value initializer has extra parentheses.");
  359. assert.doesNotThrow(function () { eval("var e = 1; ( {tuvwxy = ((( foo = 1 )))} = (e)) => { try{ } catch(e) {}}") }, "Should not throw when the default value and initializer are wrapped in extra parentheses.");
  360. assert.doesNotThrow(function () { eval("var a; ({ tyssjh = ((cspagh = 4) => a) } = 1) => { /*jjj*/ }; (function(a) { })()") }, "Should not throw when there is a nested lambda expression within destructured variable declaration.");
  361. assert.doesNotThrow(function () { eval("var a; [a = class aClass {}] = [];") }, "Should not throw when class declaration exists in destructured variable initializer.");
  362. assert.throws(function () { eval("function test5(){ var ggnzrk=function(){ }; ({ggnzrk, namespace: {}, w: [(inmgdv)]}) => { };};") }, SyntaxError, "Should throw if nested destructured declaration has a variable name in parenthesis.");
  363. assert.throws(function () { eval("function test5(){ var ggnzrk=function(){ }; ({ggnzrk, namespace: {}, w: ([inmgdv])}) => { };};") }, SyntaxError, "Should throw if nested destructured declaration is wrapped in extra parenthesis.");
  364. assert.throws(function () { eval("{ ([((iydvhw)), gpvpgk]) => { }; } var iydvhw=function(){return this};") }, SyntaxError, "Should throw if variable names in destructured declaration have extra parentheses.");
  365. assert.throws(function () { eval("(nmlwii, [((yycokb) = (1))] = (nmlwii)) => { };") }, SyntaxError, "Should throw if one or more of the lambda parameters have destructured variable declaration with initializer capturing another parameter.");
  366. assert.throws(function () { eval("({ggnzrk, w: (ggnzrk)}) => { };") }, SyntaxError, "Should throw if reused symbol in destructured variable declaration.");
  367. assert.throws(function () { eval("([x, ...((yArgs))]) => {}") }, SyntaxError, "Should throw if rest parameter name in a declaration is enclosed in parenthesis.");
  368. assert.throws(function () { eval("([x, ...(([yArgs, zArgs]))]) => {}") }, SyntaxError, "Should throw if rest parameter name in a declaration is enclosed in parenthesis.");
  369. assert.doesNotThrow(function () { eval("( {abcdef = ((((([...((abcdef))] = [1, 2, 3])) = (1))))} = (e)) => { try{ } catch(abcdef) {}}") }, "Should not throw when rest parameter name is enclosed in extra parentheses.");
  370. var a1 = 10;
  371. var b1 = 20;
  372. bar1 = ( {abcdef = (((((a1)) = (30))))} = (b1 = 40) ) => { try { throw a1; } catch(a1) { } };
  373. bar1();
  374. assert.areEqual(a1, 30, "The default value initializer should have fired for parameter in destructuring pattern.");
  375. assert.areEqual(b1, 40, "The default value block initializer should have fired for parameter in destructuring pattern.");
  376. var a2 = 10;
  377. var b2 = 20;
  378. bar2 = ( {abcdef = (((((a2)) = (30))))} = (b2 = 40) ) => { try { throw a2; } catch(a2) { } };
  379. bar2({abcdef : 50});
  380. assert.areEqual(a2, 10, "The default value initializer should NOT have fired for parameter in destructuring pattern.");
  381. assert.areEqual(b2, 20, "The default value block initializer should NOT have fired for parameter in destructuring pattern.");
  382. var a3 = 10;
  383. var b3 = 20;
  384. bar3 = ( {aa3 = a3, bb3 = b3, abcdef = (((((a3)) = (30))))} = (b3 = 40) ) =>
  385. {
  386. try
  387. {
  388. assert.areEqual(a3, undefined, "The variable a3 in the current scope should not have been assigned yet.");
  389. assert.areEqual(b3, undefined, "The variable b3 in the current scope should not have been assigned yet.");
  390. assert.areEqual(aa3, 10, "The parameter aa3 should get initialized correctly.");
  391. assert.areEqual(bb3, 20, "The parameter bb3 should get initialized correctly.");
  392. var a3 = 60;
  393. var b3 = 70;
  394. throw a3;
  395. } catch(a3) { }
  396. };
  397. bar3({abcdef : 50});
  398. assert.areEqual(a3, 10, "The variable a3 in the enclosing scope should not have been changed.");
  399. assert.areEqual(b3, 20, "The variable a3 in the enclosing scope should not have been changed.");
  400. var a4 = 10;
  401. var b4 = 15;
  402. bar4 = ( { b4 = ((xyz = 4) => a4) } = 1) => { b4 = 35; return b4; };
  403. var c4 = bar4();
  404. var d4 = (function( { a4, b4 } = { a4 : 20, b4 : 25 }) { return a4;})();
  405. assert.areEqual(a4, 10, "The variable in the enclosing scope should not have been changed.");
  406. assert.areEqual(b4, 15, "The variable in the enclosing scope should not have been changed.");
  407. assert.areEqual(c4, 35, "The variable in the enclosing scope should not have been changed.");
  408. assert.areEqual(d4, 20, "The variable in the enclosing scope should not have been changed.");
  409. }
  410. },
  411. {
  412. name: "Destructuring pattern with rest parameter has nested blocks.",
  413. body: function () {
  414. [...((a5))] = [1, 2, 3];
  415. assert.areEqual(a5, [1, 2, 3], "The rest parameter with extra parentheses gets assigned correctly.");
  416. assert.doesNotThrow(function () { eval("[...((a))] = [1, 2, 3]") }, "Should not throw when rest parameter name is enclosed in extra parentheses.");
  417. }
  418. },
  419. {
  420. name: "Destructuring bug fix - a reference from a 'this' object should be valid statement",
  421. body: function () {
  422. assert.doesNotThrow(function () { [this.x] = []; }, "array destructuring - referencing x from this in pattern is a correct syntax" );
  423. assert.doesNotThrow(function () { ({x:this.x} = {}); }, "object destructuring - referencing x from this in pattern is a correct syntax" );
  424. (function () {
  425. this.x = 1, this.y = 2;
  426. [this.x, this.y] = [this.y, this.x];
  427. assert.areEqual(this.x, 2);
  428. assert.areEqual(this.y, 1);
  429. })();
  430. assert.doesNotThrow(function () { [...this.x] = [1]; }, "array destructuring rest - referencing x from this in pattern is a correct syntax" );
  431. }
  432. },
  433. {
  434. name: "array destructuring as catch parameter can yield properly",
  435. body: function () {
  436. function * gn() {
  437. try {
  438. throw [];
  439. } catch ([c = (yield 2)]) {
  440. }
  441. };
  442. var it = gn();
  443. var k = it.next();
  444. assert.areEqual(2, k.value, "next should invoke the yield in the generator and which yields 2");
  445. }
  446. },
  447. {
  448. name: "array destructuring nested as catch parameter can yield properly",
  449. body: function () {
  450. function * gn() {
  451. try {
  452. throw [{x:[]}];
  453. } catch ([{x:[c = (yield 2)]}]) {
  454. }
  455. };
  456. var it = gn();
  457. var k = it.next();
  458. assert.areEqual(2, k.value, "next should invoke the yield in the generator and which yields 2");
  459. }
  460. },
  461. {
  462. name: "re-parsing the expression in pattern should work fine",
  463. body: function () {
  464. function test1(){
  465. function bar() { this.x = ({ y1: { z1:z1 = ((arguments)) } } = {}); { } }
  466. for (var y in {}) { };
  467. };
  468. test1();
  469. }
  470. },
  471. {
  472. name: "Invalid destructuring patterns should be early errors",
  473. body: function () {
  474. assert.throws(function () {
  475. eval("if (false) { [11] += [1, 2, 3] }");
  476. }, SyntaxError, "", "Invalid left-hand side in assignment.");
  477. assert.throws(function () {
  478. eval("if (false) { [11] = [1, 2, 3] }");
  479. }, SyntaxError, "", "Destructuring expressions can only have identifier references");
  480. }
  481. },
  482. {
  483. name: "Destructuring expression : Array expression instead of name ",
  484. body: function () {
  485. function test1(){
  486. assert.throws(function () { eval("({a: b => []} = [2])") }, SyntaxError,
  487. "", "Unexpected operator in destructuring expression");
  488. assert.throws(function () { eval("for([a => {}] in []);") }, SyntaxError,
  489. "", "Unexpected operator in destructuring expression");
  490. };
  491. test1();
  492. }
  493. }
  494. ];
  495. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });