Skip to content

Commit 794f65f

Browse files
zdenkoGeoffreyBooth
authored andcommitted
Fix #4878: Compile error when using destructuring with a splat or expansion in an array (#4879)
* fix #4878 * improvements * test * refactor
1 parent 0490eb9 commit 794f65f

File tree

3 files changed

+60
-20
lines changed

3 files changed

+60
-20
lines changed

lib/coffeescript/nodes.js

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nodes.coffee

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,8 +2408,8 @@ exports.Assign = class Assign extends Base
24082408
# Sort 'splatsAndExpans' so we can show error at first disallowed token.
24092409
objects[splatsAndExpans.sort()[1]].error "multiple splats/expansions are disallowed in an assignment"
24102410

2411-
isSplat = splats.length
2412-
isExpans = expans.length
2411+
isSplat = splats?.length > 0
2412+
isExpans = expans?.length > 0
24132413
isObject = @variable.isObject()
24142414
isArray = @variable.isArray()
24152415

@@ -2458,7 +2458,7 @@ exports.Assign = class Assign extends Base
24582458

24592459
# "Complex" `objects` are processed in a loop.
24602460
# Examples: [a, b, {c, r...}, d], [a, ..., {b, r...}, c, d]
2461-
loopObjects = (objs, vvarTxt) =>
2461+
loopObjects = (objs, vvar, vvarTxt) =>
24622462
objSpreads = hasObjSpreads objs
24632463
for obj, i in objs
24642464
# `Elision` can be skipped.
@@ -2488,16 +2488,16 @@ exports.Assign = class Assign extends Base
24882488
assigns.push new Assign(vvar, vval, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
24892489

24902490
# "Simple" `objects` can be split and compiled to arrays, [a, b, c] = arr, [a, b, c...] = arr
2491-
assignObjects = (objs, vvarTxt) =>
2491+
assignObjects = (objs, vvar, vvarTxt) =>
24922492
vvar = new Value new Arr(objs, yes)
24932493
vval = if vvarTxt instanceof Value then vvarTxt else new Value new Literal(vvarTxt)
24942494
assigns.push new Assign(vvar, vval, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
24952495

2496-
processObjects = (objs, vvarTxt) ->
2496+
processObjects = (objs, vvar, vvarTxt) ->
24972497
if complexObjects objs
2498-
loopObjects objs, vvarTxt
2498+
loopObjects objs, vvar, vvarTxt
24992499
else
2500-
assignObjects objs, vvarTxt
2500+
assignObjects objs, vvar, vvarTxt
25012501

25022502
# In case there is `Splat` or `Expansion` in `objects`,
25032503
# we can split array in two simple subarrays.
@@ -2514,7 +2514,7 @@ exports.Assign = class Assign extends Base
25142514
expIdx = splatsAndExpans[0]
25152515
leftObjs = objects.slice 0, expIdx + (if isSplat then 1 else 0)
25162516
rightObjs = objects.slice expIdx + 1
2517-
processObjects leftObjs, vvarText if leftObjs.length isnt 0
2517+
processObjects leftObjs, vvar, vvarText if leftObjs.length isnt 0
25182518
if rightObjs.length isnt 0
25192519
# Slice or splice `objects`.
25202520
refExp = switch
@@ -2524,10 +2524,10 @@ exports.Assign = class Assign extends Base
25242524
restVar = refExp
25252525
refExp = o.scope.freeVariable 'ref'
25262526
assigns.push [@makeCode(refExp + ' = '), restVar.compileToFragments(o, LEVEL_LIST)...]
2527-
processObjects rightObjs, refExp
2527+
processObjects rightObjs, vvar, refExp
25282528
else
25292529
# There is no `Splat` or `Expansion` in `objects`.
2530-
processObjects objects, vvarText
2530+
processObjects objects, vvar, vvarText
25312531
assigns.push vvar unless top or @subpattern
25322532
fragments = @joinFragmentArrays assigns, ', '
25332533
if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments

test/assignment.coffee

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,3 +945,43 @@ test "#4673: complex destructured object spread variables", ->
945945

946946
{{g}...} = g: 1
947947
eq g, 1
948+
949+
test "#4878: Compile error when using destructuring with a splat or expansion in an array", ->
950+
arr = ['a', 'b', 'c', 'd']
951+
952+
f1 = (list) ->
953+
[first, ..., last] = list
954+
955+
f2 = (list) ->
956+
[first..., last] = list
957+
958+
f3 = (list) ->
959+
([first, ...] = list); first
960+
961+
f4 = (list) ->
962+
([first, ...rest] = list); rest
963+
964+
arrayEq f1(arr), arr
965+
arrayEq f2(arr), arr
966+
arrayEq f3(arr), 'a'
967+
arrayEq f4(arr), ['b', 'c', 'd']
968+
969+
foo = (list) ->
970+
ret =
971+
if list?.length > 0
972+
[first, ..., last] = list
973+
[first, last]
974+
else
975+
[]
976+
977+
arrayEq foo(arr), ['a', 'd']
978+
979+
bar = (list) ->
980+
ret =
981+
if list?.length > 0
982+
[first, ...rest] = list
983+
[first, rest]
984+
else
985+
[]
986+
987+
arrayEq bar(arr), ['a', ['b', 'c', 'd']]

0 commit comments

Comments
 (0)