From 2b83dfbf4011fce960abc5c7d372a672e97940f0 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Mon, 13 Apr 2015 14:10:03 -0700 Subject: [PATCH] Properly emit nested destructuring in rest elements (fixes #2587) --- src/compiler/emitter.ts | 22 +++++++----- src/compiler/utilities.ts | 7 ++++ ...clarationEmitDestructuringArrayPattern4.js | 16 ++++----- .../reference/declarationsAndAssignments.js | 36 +++++++++---------- .../reference/nonIterableRestElement1.js | 3 +- .../reference/nonIterableRestElement3.js | 3 +- .../restElementWithAssignmentPattern3.js | 3 +- .../restElementWithAssignmentPattern4.js | 3 +- .../restElementWithAssignmentPattern5.js | 2 +- .../restElementWithBindingPattern.js | 2 +- .../restElementWithBindingPattern2.js | 2 +- .../reference/restElementWithInitializer1.js | 2 +- .../reference/restElementWithInitializer2.js | 3 +- .../restElementWithNullInitializer.js | 8 ++--- 14 files changed, 63 insertions(+), 49 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a06adbb0d533e..ce88394d6bbde 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2558,7 +2558,7 @@ var __param = this.__param || function(index, decorator) { return function (targ return node; } - function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier): Expression { + function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { if (propName.kind !== SyntaxKind.Identifier) { return createElementAccessExpression(object, propName); } @@ -2566,6 +2566,16 @@ var __param = this.__param || function(index, decorator) { return function (targ return createPropertyAccessExpression(object, propName); } + function createSliceCall(value: Expression, sliceIndex: number): CallExpression { + let call = createSynthesizedNode(SyntaxKind.CallExpression); + let sliceIdentifier = createSynthesizedNode(SyntaxKind.Identifier); + sliceIdentifier.text = "slice"; + call.expression = createPropertyAccessExpression(value, sliceIdentifier); + call.arguments = >createSynthesizedNodeArray(); + call.arguments[0] = createNumericLiteral(sliceIndex); + return call; + } + function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) { let properties = target.properties; if (properties.length !== 1) { @@ -2576,7 +2586,7 @@ var __param = this.__param || function(index, decorator) { return function (targ for (let p of properties) { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { // TODO(andersh): Computed property support - let propName = ((p).name); + let propName = ((p).name); emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); } } @@ -2596,9 +2606,7 @@ var __param = this.__param || function(index, decorator) { return function (targ emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i))); } else if (i === elements.length - 1) { - value = ensureIdentifier(value); - emitAssignment((e).expression, value); - write(".slice(" + i + ")"); + emitDestructuringAssignment((e).expression, createSliceCall(value, i)); } } } @@ -2670,9 +2678,7 @@ var __param = this.__param || function(index, decorator) { return function (targ emitBindingElement(element, createElementAccessExpression(value, createNumericLiteral(i))); } else if (i === elements.length - 1) { - value = ensureIdentifier(value); - emitAssignment(element.name, value); - write(".slice(" + i + ")"); + emitBindingElement(element, createSliceCall(value, i)); } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b0c50fc7f669b..e2be214139870 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1379,6 +1379,13 @@ module ts { return node; } + export function createSynthesizedNodeArray(): NodeArray { + var array = >[]; + array.pos = -1; + array.end = -1; + return array; + } + /* @internal */ export function createDiagnosticCollection(): DiagnosticCollection { let nonFileDiagnostics: Diagnostic[] = []; diff --git a/tests/baselines/reference/declarationEmitDestructuringArrayPattern4.js b/tests/baselines/reference/declarationEmitDestructuringArrayPattern4.js index f19a4a840bf23..c26c9d1fff38b 100644 --- a/tests/baselines/reference/declarationEmitDestructuringArrayPattern4.js +++ b/tests/baselines/reference/declarationEmitDestructuringArrayPattern4.js @@ -10,14 +10,14 @@ var [x18, y18, ...a12] = [1, "hello", true]; var [x19, y19, z19, ...a13] = [1, "hello", true]; //// [declarationEmitDestructuringArrayPattern4.js] -var _a = [1, 2, 3], a5 = _a.slice(0); -var _b = [1, 2, 3], x14 = _b[0], a6 = _b.slice(1); -var _c = [1, 2, 3], x15 = _c[0], y15 = _c[1], a7 = _c.slice(2); -var _d = [1, 2, 3], x16 = _d[0], y16 = _d[1], z16 = _d[2], a8 = _d.slice(3); -var _e = [1, "hello", true], a9 = _e.slice(0); -var _f = [1, "hello", true], x17 = _f[0], a10 = _f.slice(1); -var _g = [1, "hello", true], x18 = _g[0], y18 = _g[1], a12 = _g.slice(2); -var _h = [1, "hello", true], x19 = _h[0], y19 = _h[1], z19 = _h[2], a13 = _h.slice(3); +var a5 = ([1, 2, 3]).slice(0); +var _a = [1, 2, 3], x14 = _a[0], a6 = _a.slice(1); +var _b = [1, 2, 3], x15 = _b[0], y15 = _b[1], a7 = _b.slice(2); +var _c = [1, 2, 3], x16 = _c[0], y16 = _c[1], z16 = _c[2], a8 = _c.slice(3); +var a9 = ([1, "hello", true]).slice(0); +var _d = [1, "hello", true], x17 = _d[0], a10 = _d.slice(1); +var _e = [1, "hello", true], x18 = _e[0], y18 = _e[1], a12 = _e.slice(2); +var _f = [1, "hello", true], x19 = _f[0], y19 = _f[1], z19 = _f[2], a13 = _f.slice(3); //// [declarationEmitDestructuringArrayPattern4.d.ts] diff --git a/tests/baselines/reference/declarationsAndAssignments.js b/tests/baselines/reference/declarationsAndAssignments.js index 032f4cb0e633d..8cb3bc68c0497 100644 --- a/tests/baselines/reference/declarationsAndAssignments.js +++ b/tests/baselines/reference/declarationsAndAssignments.js @@ -321,28 +321,28 @@ function f20() { var x; var y; var z; - var _a = [1, 2, 3], a = _a.slice(0); - var _b = [1, 2, 3], x = _b[0], a = _b.slice(1); - var _c = [1, 2, 3], x = _c[0], y = _c[1], a = _c.slice(2); - var _d = [1, 2, 3], x = _d[0], y = _d[1], z = _d[2], a = _d.slice(3); - _e = [1, 2, 3], a = _e.slice(0); - _f = [1, 2, 3], x = _f[0], a = _f.slice(1); - _g = [1, 2, 3], x = _g[0], y = _g[1], a = _g.slice(2); - _h = [1, 2, 3], x = _h[0], y = _h[1], z = _h[2], a = _h.slice(3); - var _e, _f, _g, _h; + var a = ([1, 2, 3]).slice(0); + var _a = [1, 2, 3], x = _a[0], a = _a.slice(1); + var _b = [1, 2, 3], x = _b[0], y = _b[1], a = _b.slice(2); + var _c = [1, 2, 3], x = _c[0], y = _c[1], z = _c[2], a = _c.slice(3); + a = ([1, 2, 3]).slice(0); + _d = [1, 2, 3], x = _d[0], a = _d.slice(1); + _e = [1, 2, 3], x = _e[0], y = _e[1], a = _e.slice(2); + _f = [1, 2, 3], x = _f[0], y = _f[1], z = _f[2], a = _f.slice(3); + var _d, _e, _f; } function f21() { var a; var x; var y; var z; - var _a = [1, "hello", true], a = _a.slice(0); - var _b = [1, "hello", true], x = _b[0], a = _b.slice(1); - var _c = [1, "hello", true], x = _c[0], y = _c[1], a = _c.slice(2); - var _d = [1, "hello", true], x = _d[0], y = _d[1], z = _d[2], a = _d.slice(3); - _e = [1, "hello", true], a = _e.slice(0); - _f = [1, "hello", true], x = _f[0], a = _f.slice(1); - _g = [1, "hello", true], x = _g[0], y = _g[1], a = _g.slice(2); - _h = [1, "hello", true], x = _h[0], y = _h[1], z = _h[2], a = _h.slice(3); - var _e, _f, _g, _h; + var a = ([1, "hello", true]).slice(0); + var _a = [1, "hello", true], x = _a[0], a = _a.slice(1); + var _b = [1, "hello", true], x = _b[0], y = _b[1], a = _b.slice(2); + var _c = [1, "hello", true], x = _c[0], y = _c[1], z = _c[2], a = _c.slice(3); + a = ([1, "hello", true]).slice(0); + _d = [1, "hello", true], x = _d[0], a = _d.slice(1); + _e = [1, "hello", true], x = _e[0], y = _e[1], a = _e.slice(2); + _f = [1, "hello", true], x = _f[0], y = _f[1], z = _f[2], a = _f.slice(3); + var _d, _e, _f; } diff --git a/tests/baselines/reference/nonIterableRestElement1.js b/tests/baselines/reference/nonIterableRestElement1.js index 0b0d97aed2f08..70aeb32de5f8a 100644 --- a/tests/baselines/reference/nonIterableRestElement1.js +++ b/tests/baselines/reference/nonIterableRestElement1.js @@ -4,5 +4,4 @@ var c = {}; //// [nonIterableRestElement1.js] var c = {}; -_a = ["", 0], c = _a.slice(0); -var _a; +c = (["", 0]).slice(0); diff --git a/tests/baselines/reference/nonIterableRestElement3.js b/tests/baselines/reference/nonIterableRestElement3.js index 2901699a878d8..dc344256c354f 100644 --- a/tests/baselines/reference/nonIterableRestElement3.js +++ b/tests/baselines/reference/nonIterableRestElement3.js @@ -4,5 +4,4 @@ var c = { bogus: 0 }; //// [nonIterableRestElement3.js] var c = { bogus: 0 }; -_a = ["", 0], c = _a.slice(0); -var _a; +c = (["", 0]).slice(0); diff --git a/tests/baselines/reference/restElementWithAssignmentPattern3.js b/tests/baselines/reference/restElementWithAssignmentPattern3.js index 405d39446d019..1ca504fbd6dab 100644 --- a/tests/baselines/reference/restElementWithAssignmentPattern3.js +++ b/tests/baselines/reference/restElementWithAssignmentPattern3.js @@ -6,4 +6,5 @@ var tuple: [string, number] = ["", 1]; //// [restElementWithAssignmentPattern3.js] var a, b; var tuple = ["", 1]; -[a, b = 0] = tuple.slice(0); +_a = tuple.slice(0), a = _a[0], _b = _a[1], b = _b === void 0 ? 0 : _b; +var _a, _b; diff --git a/tests/baselines/reference/restElementWithAssignmentPattern4.js b/tests/baselines/reference/restElementWithAssignmentPattern4.js index 801510252a2bc..b47a2adea0119 100644 --- a/tests/baselines/reference/restElementWithAssignmentPattern4.js +++ b/tests/baselines/reference/restElementWithAssignmentPattern4.js @@ -6,4 +6,5 @@ var tuple: [string, number] = ["", 1]; //// [restElementWithAssignmentPattern4.js] var a, b; var tuple = ["", 1]; -{ 0: a = "", b: b } = tuple.slice(0); +_a = tuple.slice(0), _b = _a[0], a = _b === void 0 ? "" : _b, b = _a.b; +var _a, _b; diff --git a/tests/baselines/reference/restElementWithAssignmentPattern5.js b/tests/baselines/reference/restElementWithAssignmentPattern5.js index 4d4068abcd915..0906289e35b08 100644 --- a/tests/baselines/reference/restElementWithAssignmentPattern5.js +++ b/tests/baselines/reference/restElementWithAssignmentPattern5.js @@ -4,5 +4,5 @@ var s: string, s2: string; //// [restElementWithAssignmentPattern5.js] var s, s2; -_a = ["", ""], [s, s2] = _a.slice(0); +_a = (["", ""]).slice(0), s = _a[0], s2 = _a[1]; var _a; diff --git a/tests/baselines/reference/restElementWithBindingPattern.js b/tests/baselines/reference/restElementWithBindingPattern.js index 4c6bc11df6689..d26015ec93300 100644 --- a/tests/baselines/reference/restElementWithBindingPattern.js +++ b/tests/baselines/reference/restElementWithBindingPattern.js @@ -2,4 +2,4 @@ var [...[a, b]] = [0, 1]; //// [restElementWithBindingPattern.js] -var _a = [0, 1], [a, b] = _a.slice(0); +var _a = ([0, 1]).slice(0), a = _a[0], b = _a[1]; diff --git a/tests/baselines/reference/restElementWithBindingPattern2.js b/tests/baselines/reference/restElementWithBindingPattern2.js index 0aedebf103c42..bb49c71419e37 100644 --- a/tests/baselines/reference/restElementWithBindingPattern2.js +++ b/tests/baselines/reference/restElementWithBindingPattern2.js @@ -2,4 +2,4 @@ var [...{0: a, b }] = [0, 1]; //// [restElementWithBindingPattern2.js] -var _a = [0, 1], { 0: a, b } = _a.slice(0); +var _a = ([0, 1]).slice(0), a = _a[0], b = _a.b; diff --git a/tests/baselines/reference/restElementWithInitializer1.js b/tests/baselines/reference/restElementWithInitializer1.js index 26df58e3cf3fa..b0d35cdf47fd8 100644 --- a/tests/baselines/reference/restElementWithInitializer1.js +++ b/tests/baselines/reference/restElementWithInitializer1.js @@ -5,4 +5,4 @@ var [...x = a] = a; // Error, rest element cannot have initializer //// [restElementWithInitializer1.js] var a; -var x = a.slice(0); // Error, rest element cannot have initializer +var _a = a.slice(0), x = _a === void 0 ? a : _a; // Error, rest element cannot have initializer diff --git a/tests/baselines/reference/restElementWithInitializer2.js b/tests/baselines/reference/restElementWithInitializer2.js index 8874f6a83d0a7..09ec76bdfb4d5 100644 --- a/tests/baselines/reference/restElementWithInitializer2.js +++ b/tests/baselines/reference/restElementWithInitializer2.js @@ -7,4 +7,5 @@ var x: number[]; //// [restElementWithInitializer2.js] var a; var x; -x = a = a.slice(0); // Error, rest element cannot have initializer +_a = a.slice(0), x = _a === void 0 ? a : _a; // Error, rest element cannot have initializer +var _a; diff --git a/tests/baselines/reference/restElementWithNullInitializer.js b/tests/baselines/reference/restElementWithNullInitializer.js index 9f326602fb837..ac378b0905bb5 100644 --- a/tests/baselines/reference/restElementWithNullInitializer.js +++ b/tests/baselines/reference/restElementWithNullInitializer.js @@ -14,14 +14,14 @@ function foo4([...r] = []) { //// [restElementWithNullInitializer.js] function foo1(_a) { - var _b = _a === void 0 ? null : _a, r = _b.slice(0); + var r = (_a === void 0 ? null : _a).slice(0); } function foo2(_a) { - var _b = _a === void 0 ? undefined : _a, r = _b.slice(0); + var r = (_a === void 0 ? undefined : _a).slice(0); } function foo3(_a) { - var _b = _a === void 0 ? {} : _a, r = _b.slice(0); + var r = (_a === void 0 ? {} : _a).slice(0); } function foo4(_a) { - var _b = _a === void 0 ? [] : _a, r = _b.slice(0); + var r = (_a === void 0 ? [] : _a).slice(0); }