From 5bc85b8f6d0065bb3d8cea04393f2e7d50e8bbed Mon Sep 17 00:00:00 2001 From: zdenko Date: Mon, 4 Dec 2017 17:00:45 +0100 Subject: [PATCH] Fix #4798: Incorrect output for object rest destructuring inside array destructuring (#4799) * fix #4798 * additional tests --- lib/coffeescript/nodes.js | 12 +++++++----- src/nodes.coffee | 7 ++++--- test/assignment.coffee | 11 +++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/coffeescript/nodes.js b/lib/coffeescript/nodes.js index fb456691..671c2184 100644 --- a/lib/coffeescript/nodes.js +++ b/lib/coffeescript/nodes.js @@ -3212,7 +3212,7 @@ // we've been assigned to, for correct internal references. If the variable // has not been seen yet within the current scope, declare it. compileNode(o) { - var answer, compiledName, isValue, j, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase; + var answer, compiledName, hasSplat, isValue, j, name, objDestructAnswer, properties, prototype, ref1, ref2, ref3, ref4, ref5, val, varBase; isValue = this.variable instanceof Value; if (isValue) { // When compiling `@variable`, remember if it is part of a function parameter. @@ -3226,12 +3226,14 @@ // know that, so that those nodes know that they’re assignable as // destructured variables. this.variable.base.lhs = true; - if (!this.variable.isAssignable()) { + // Check if @variable contains Obj with splats. + hasSplat = this.variable.contains(function(node) { + return node instanceof Obj && node.hasSplat(); + }); + if (!this.variable.isAssignable() || this.variable.isArray() && hasSplat) { return this.compileDestructuring(o); } - if (this.variable.isObject() && this.variable.contains(function(node) { - return node instanceof Obj && node.hasSplat(); - })) { + if (this.variable.isObject() && hasSplat) { // Object destructuring. Can be removed once ES proposal hits Stage 4. objDestructAnswer = this.compileObjectDestruct(o); } diff --git a/src/nodes.coffee b/src/nodes.coffee index 8ff857f9..f97d57ea 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -2156,10 +2156,11 @@ exports.Assign = class Assign extends Base # know that, so that those nodes know that they’re assignable as # destructured variables. @variable.base.lhs = yes - return @compileDestructuring o unless @variable.isAssignable() + # Check if @variable contains Obj with splats. + hasSplat = @variable.contains (node) -> node instanceof Obj and node.hasSplat() + return @compileDestructuring o if not @variable.isAssignable() or @variable.isArray() and hasSplat # Object destructuring. Can be removed once ES proposal hits Stage 4. - objDestructAnswer = @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) -> - node instanceof Obj and node.hasSplat() + objDestructAnswer = @compileObjectDestruct(o) if @variable.isObject() and hasSplat return objDestructAnswer if objDestructAnswer return @compileSplice o if @variable.isSplice() diff --git a/test/assignment.coffee b/test/assignment.coffee index b2bf3e35..38d837c9 100644 --- a/test/assignment.coffee +++ b/test/assignment.coffee @@ -185,6 +185,17 @@ test "#4787 destructuring of objects within arrays", -> eq b, arr[1].b deepEqual {a, b}, arr[1] +test "#4798 destructuring of objects with splat within arrays", -> + arr = [1, {a:1, b:2}] + [...,{a, r...}] = arr + eq a, 1 + deepEqual r, {b:2} + [b, {q...}] = arr + eq b, 1 + deepEqual q, arr[1] + eq q.b, r.b + eq q.a, a + test "destructuring assignment with splats", -> a = {}; b = {}; c = {}; d = {}; e = {} [x,y...,z] = [a,b,c,d,e]