| // Any copyright is dedicated to the Public Domain. |
| // http://creativecommons.org/licenses/publicdomain/ |
| |
| //----------------------------------------------------------------------------- |
| var BUGNUMBER = 1146136; |
| var summary = |
| 'Parenthesized "destructuring patterns" are not usable as destructuring ' + |
| 'patterns'; |
| |
| print(BUGNUMBER + ": " + summary); |
| |
| /************** |
| * BEGIN TEST * |
| **************/ |
| |
| // Don't pollute the top-level script with eval references. |
| var savedEval = this[String.fromCharCode(101, 118, 97, 108)]; |
| |
| function checkError(code, nonstrictErr, strictErr) |
| { |
| function helper(exec, prefix, err) |
| { |
| var fullCode = prefix + code; |
| try |
| { |
| var f = exec(fullCode); |
| |
| var error = |
| "no early error, parsed code <" + fullCode + "> using " + exec.name; |
| if (typeof f === "function") |
| { |
| try |
| { |
| f(); |
| error += ", and the function can be called without error"; |
| } |
| catch (e) |
| { |
| error +=", and calling the function throws " + e; |
| } |
| } |
| |
| throw new Error(error); |
| } |
| catch (e) |
| { |
| assertEq(e instanceof err, true, |
| "expected " + err.name + ", got " + e + " " + |
| "for code <" + fullCode + "> when parsed using " + exec.name); |
| } |
| } |
| |
| helper(Function, "", nonstrictErr); |
| helper(Function, "'use strict'; ", strictErr); |
| helper(savedEval, "", nonstrictErr); |
| helper(savedEval, "'use strict'; ", strictErr); |
| } |
| |
| // Parenthesized destructuring patterns don't trigger grammar refinement, so we |
| // get the currently-usual ReferenceError for an invalid assignment target, per |
| // 12.14.1 second bullet. |
| checkError("var a, b; ([a, b]) = [1, 2];", ReferenceError, ReferenceError); |
| checkError("var a, b; ({a, b}) = { a: 1, b: 2 };", ReferenceError, ReferenceError); |
| |
| // *Nested* parenthesized destructuring patterns, on the other hand, do trigger |
| // grammar refinement. But subtargets in a destructuring pattern must be |
| // either object/array literals that match the destructuring pattern refinement |
| // *or* valid simple assignment targets (or such things with a default, with the |
| // entire subtarget unparenthesized: |a = 3| is fine, |(a) = 3| is fine for |
| // destructuring in an expression, |(a = 3)| is forbidden). Parenthesized |
| // object/array patterns are neither. And so 12.14.5.1 third bullet requires an |
| // early SyntaxError. |
| checkError("var a, b; ({ a: ({ b: b }) } = { a: { b: 42 } });", SyntaxError, SyntaxError); |
| checkError("var a, b; ({ a: { b: (b = 7) } } = { a: {} });", SyntaxError, SyntaxError); |
| checkError("var a, b; ({ a: ([b]) } = { a: [42] });", SyntaxError, SyntaxError); |
| checkError("var a, b; [(a = 5)] = [1];", SyntaxError, SyntaxError); |
| checkError("var a, b; ({ a: (b = 7)} = { b: 1 });", SyntaxError, SyntaxError); |
| |
| Function("var a, b; [(a), b] = [1, 2];")(); |
| Function("var a, b; [(a) = 5, b] = [1, 2];")(); |
| Function("var a, b; [(arguments), b] = [1, 2];")(); |
| Function("var a, b; [(arguments) = 5, b] = [1, 2];")(); |
| Function("var a, b; [(eval), b] = [1, 2];")(); |
| Function("var a, b; [(eval) = 5, b] = [1, 2];")(); |
| |
| var repair = {}, demolition = {}; |
| |
| Function("var a, b; [(repair.man), b] = [1, 2];")(); |
| Function("var a, b; [(demolition['man']) = 'motel', b] = [1, 2];")(); |
| Function("var a, b; [(demolition['man' + {}]) = 'motel', b] = [1, 2];")(); // evade constant-folding |
| |
| function classesEnabled() |
| { |
| try |
| { |
| new Function("class B { constructor() { } }; class D extends B { constructor() { super(); } }"); |
| return true; |
| } |
| catch (e if e instanceof SyntaxError) |
| { |
| return false; |
| } |
| } |
| |
| if (classesEnabled()) |
| { |
| Function("var a, b; var obj = { x() { [(super.man), b] = [1, 2]; } };")(); |
| Function("var a, b; var obj = { x() { [(super[8]) = 'motel', b] = [1, 2]; } };")(); |
| Function("var a, b; var obj = { x() { [(super[8 + {}]) = 'motel', b] = [1, 2]; } };")(); // evade constant-folding |
| } |
| |
| // As noted above, when the assignment element has an initializer, the |
| // assignment element must not be parenthesized. |
| checkError("var a, b; [(repair.man = 17)] = [1];", SyntaxError, SyntaxError); |
| checkError("var a, b; [(demolition['man'] = 'motel')] = [1, 2];", SyntaxError, SyntaxError); |
| checkError("var a, b; [(demolition['man' + {}] = 'motel')] = [1];", SyntaxError, SyntaxError); // evade constant-folding |
| if (classesEnabled()) |
| { |
| checkError("var a, b; var obj = { x() { [(super.man = 5)] = [1]; } };", SyntaxError, SyntaxError); |
| checkError("var a, b; var obj = { x() { [(super[8] = 'motel')] = [1]; } };", SyntaxError, SyntaxError); |
| checkError("var a, b; var obj = { x() { [(super[8 + {}] = 'motel')] = [1]; } };", SyntaxError, SyntaxError); // evade constant-folding |
| } |
| |
| // In strict mode, assignment to funcall *immediately* triggers ReferenceError |
| // before we can recognize this doesn't even match the destructuring grammar to |
| // begin with. Bleh. :-( Probably they should all be made SyntaxError in the |
| // specs; see <https://bugs.ecmascript.org/show_bug.cgi?id=4375>. |
| checkError("var a, b; [f() = 'ohai', b] = [1, 2];", SyntaxError, ReferenceError); |
| checkError("var a, b; [(f()) = 'kthxbai', b] = [1, 2];", SyntaxError, ReferenceError); |
| |
| Function("var a, b; ({ a: (a), b} = { a: 1, b: 2 });")(); |
| Function("var a, b; ({ a: (a) = 5, b} = { a: 1, b: 2 });")(); |
| |
| |
| /******************************************************************************/ |
| |
| if (typeof reportCompare === "function") |
| reportCompare(true, true); |
| |
| print("Tests complete"); |