Skip to content

Commit 5525b2b

Browse files
authored
Merge pull request #4652 from GeoffreyBooth/bug-fix-4651
[CS2] Fix #4651: object spread destructuring bug
2 parents fe5ff39 + c212e6e commit 5525b2b

File tree

3 files changed

+65
-10
lines changed

3 files changed

+65
-10
lines changed

lib/coffeescript/nodes.js

+27-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nodes.coffee

+15-4
Original file line numberDiff line numberDiff line change
@@ -2120,8 +2120,9 @@ exports.Assign = class Assign extends Base
21202120
@variable.base.lhs = yes
21212121
return @compileDestructuring o unless @variable.isAssignable()
21222122
# Object destructuring. Can be removed once ES proposal hits Stage 4.
2123-
return @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) ->
2123+
objDestructAnswer = @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) ->
21242124
node instanceof Obj and node.hasSplat()
2125+
return objDestructAnswer if objDestructAnswer
21252126

21262127
return @compileSplice o if @variable.isSplice()
21272128
return @compileConditional o if @context in ['||=', '&&=', '?=']
@@ -2214,12 +2215,16 @@ exports.Assign = class Assign extends Base
22142215
traverseRest = (properties, source) =>
22152216
restElements = []
22162217
restIndex = undefined
2218+
source = new Value source unless source.properties?
22172219

22182220
for prop, index in properties
2221+
nestedSourceDefault = nestedSource = nestedProperties = null
22192222
setScopeVar prop.unwrap()
22202223
if prop instanceof Assign
22212224
# prop is `k: expr`, we need to check `expr` for nested splats
22222225
if prop.value.isObject?()
2226+
# prop is `k = {...} `
2227+
continue unless prop.context is 'object'
22232228
# prop is `k: {...}`
22242229
nestedProperties = prop.value.base.properties
22252230
else if prop.value instanceof Assign and prop.value.variable.isObject()
@@ -2245,13 +2250,19 @@ exports.Assign = class Assign extends Base
22452250

22462251
restElements
22472252

2248-
# Cache the value for reuse with rest elements
2249-
[@value, valueRef] = @value.cache o
2253+
# Cache the value for reuse with rest elements.
2254+
if @value.shouldCache()
2255+
valueRefTemp = new IdentifierLiteral o.scope.freeVariable 'ref', reserve: false
2256+
else
2257+
valueRefTemp = @value.base
22502258

22512259
# Find all rest elements.
2252-
restElements = traverseRest @variable.base.properties, valueRef
2260+
restElements = traverseRest @variable.base.properties, valueRefTemp
2261+
return no unless restElements and restElements.length > 0
22532262

2263+
[@value, valueRef] = @value.cache o
22542264
result = new Block [@]
2265+
22552266
for restElement in restElements
22562267
value = new Call new Value(new Literal utility 'objectWithoutKeys', o), [restElement.source, restElement.excludeProps]
22572268
result.push new Assign restElement.name, value

test/assignment.coffee

+23
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,29 @@ test "destructuring assignment with multiple splats in different objects", ->
296296
deepEqual a, val: 1
297297
deepEqual b, val: 2
298298

299+
o = {
300+
props: {
301+
p: {
302+
n: 1
303+
m: 5
304+
}
305+
s: 6
306+
}
307+
}
308+
{p: {m, q..., t = {obj...}}, r...} = o.props
309+
eq m, o.props.p.m
310+
deepEqual r, s: 6
311+
deepEqual q, n: 1
312+
deepEqual t, obj
313+
314+
@props = o.props
315+
{p: {m}, r...} = @props
316+
eq m, @props.p.m
317+
deepEqual r, s: 6
318+
319+
{p: {m}, r...} = {o.props..., p:{m:9}}
320+
eq m, 9
321+
299322
# Should not trigger implicit call, e.g. rest ... => rest(...)
300323
{
301324
a: {

0 commit comments

Comments
 (0)