Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 8adfd2b

Browse files
butterunderflowButter934cristianoc
authored
Add spread element check when the last element is a spread. (#673)
* fix issue (#670) * formatting issue * rename to improve readability * comment on the boolean value indicates spread expr * formatting issue * fix syntax error in error message * update CHANGELOG.md * tweak Co-authored-by: zdh <[email protected]> Co-authored-by: Cristiano Calcagno <[email protected]>
1 parent aba31d3 commit 8adfd2b

File tree

3 files changed

+33
-16
lines changed

3 files changed

+33
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
- Fix printing of comments inside JSX tag https://github.com/rescript-lang/syntax/pull/664
3939
- Fix issue where formatter erases tail comments inside JSX tag https://github.com/rescript-lang/syntax/issues/663
4040
- Fix issue where the JSX prop has type annotation of the first class module https://github.com/rescript-lang/syntax/pull/666
41+
- Fix issue where a spread `...x` in non-last position would not be reported as syntax error https://github.com/rescript-lang/syntax/pull/673/
4142

4243
#### :eyeglasses: Spec Compliance
4344

src/res_core.ml

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ module ErrorMessages = struct
5050
let listPatternSpread =
5151
"List pattern matches only supports one `...` spread, at the end.\n\
5252
Explanation: a list spread at the tail is efficient, but a spread in the \
53-
middle would create new list[s]; out of performance concern, our pattern \
53+
middle would create new lists; out of performance concern, our pattern \
5454
matching currently guarantees to never create new intermediate data."
5555

5656
let recordPatternSpread =
@@ -84,8 +84,8 @@ module ErrorMessages = struct
8484
let listExprSpread =
8585
"Lists can only have one `...` spread, and at the end.\n\
8686
Explanation: lists are singly-linked list, where a node contains a value \
87-
and points to the next node. `list[a, ...bc]` efficiently creates a new \
88-
item and links `bc` as its next nodes. `[...bc, a]` would be expensive, \
87+
and points to the next node. `list{a, ...bc}` efficiently creates a new \
88+
item and links `bc` as its next nodes. `list{...bc, a}` would be expensive, \
8989
as it'd need to traverse `bc` and prepend each item to `a` one by one. We \
9090
therefore disallow such syntax sugar.\n\
9191
Solution: directly use `concat`."
@@ -3716,25 +3716,27 @@ and parseSpreadExprRegion p =
37163716
| _ -> None
37173717

37183718
and parseListExpr ~startPos p =
3719-
let listExprs =
3719+
let check_all_non_spread_exp exprs =
3720+
exprs
3721+
|> List.map (fun (spread, expr) ->
3722+
if spread then
3723+
Parser.err p (Diagnostics.message ErrorMessages.listExprSpread);
3724+
expr)
3725+
|> List.rev
3726+
in
3727+
let listExprsRev =
37203728
parseCommaDelimitedReversedList p ~grammar:Grammar.ListExpr ~closing:Rbrace
37213729
~f:parseSpreadExprRegion
37223730
in
37233731
Parser.expect Rbrace p;
37243732
let loc = mkLoc startPos p.prevEndPos in
3725-
match listExprs with
3726-
| (true, expr) :: exprs ->
3727-
let exprs = exprs |> List.map snd |> List.rev in
3733+
match listExprsRev with
3734+
| (true, (* spread expression *)
3735+
expr) :: exprs ->
3736+
let exprs = check_all_non_spread_exp exprs in
37283737
makeListExpression loc exprs (Some expr)
37293738
| exprs ->
3730-
let exprs =
3731-
exprs
3732-
|> List.map (fun (spread, expr) ->
3733-
if spread then
3734-
Parser.err p (Diagnostics.message ErrorMessages.listExprSpread);
3735-
expr)
3736-
|> List.rev
3737-
in
3739+
let exprs = check_all_non_spread_exp exprs in
37383740
makeListExpression loc exprs None
37393741

37403742
(* Overparse ... and give a nice error message *)

tests/parsing/errors/other/expected/spread.res.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ Explanation: you can't collect a subset of a record's field into its own record,
4949
Solution: you need to pull out each field you want explicitly.
5050

5151

52+
Syntax error!
53+
tests/parsing/errors/other/spread.res:8:1-3
54+
55+
6 │
56+
7 │ let myList = list{...x, ...y}
57+
8 │ let list{...x, ...y} = myList
58+
9 │
59+
10 │ type t = {...a}
60+
61+
Lists can only have one `...` spread, and at the end.
62+
Explanation: lists are singly-linked list, where a node contains a value and points to the next node. `list{a, ...bc}` efficiently creates a new item and links `bc` as its next nodes. `list{...bc, a}` would be expensive, as it'd need to traverse `bc` and prepend each item to `a` one by one. We therefore disallow such syntax sugar.
63+
Solution: directly use `concat`.
64+
65+
5266
Syntax error!
5367
tests/parsing/errors/other/spread.res:8:13-22
5468

@@ -59,7 +73,7 @@ Solution: you need to pull out each field you want explicitly.
5973
10 │ type t = {...a}
6074

6175
List pattern matches only supports one `...` spread, at the end.
62-
Explanation: a list spread at the tail is efficient, but a spread in the middle would create new list[s]; out of performance concern, our pattern matching currently guarantees to never create new intermediate data.
76+
Explanation: a list spread at the tail is efficient, but a spread in the middle would create new lists; out of performance concern, our pattern matching currently guarantees to never create new intermediate data.
6377

6478

6579
Syntax error!

0 commit comments

Comments
 (0)