Skip to content

Commit ce58ff9

Browse files
committed
parse single spreads in variant payloads as inline records with single spread
1 parent d117851 commit ce58ff9

File tree

3 files changed

+48
-44
lines changed

3 files changed

+48
-44
lines changed

jscomp/syntax/src/res_core.ml

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,6 @@ module ErrorMessages = struct
134134
let stringInterpolationInPattern =
135135
"String interpolation is not supported in pattern matching."
136136

137-
let spreadInRecordDeclaration =
138-
"A record type declaration doesn't support the ... spread. Only an object \
139-
(with quoted field names) does."
140-
141137
let objectQuotedFieldName name =
142138
"An object type declaration needs quoted field names. Did you mean \""
143139
^ name ^ "\"?"
@@ -482,6 +478,11 @@ let lidentOfPath longident =
482478
| [] -> ""
483479
| ident :: _ -> ident
484480

481+
let makeRecordDotField ~dotdotdotStart ~dotdotdotEnd ~loc typ =
482+
Ast_helper.Type.field ~loc
483+
{txt = "..."; loc = mkLoc dotdotdotStart dotdotdotEnd}
484+
typ
485+
485486
let makeNewtypes ~attrs ~loc newtypes exp =
486487
let expr =
487488
List.fold_right
@@ -4579,40 +4580,37 @@ and parseConstrDeclArgs p =
45794580
(* start of object type spreading, e.g. `User({...a, "u": int})` *)
45804581
Parser.next p;
45814582
let typ = parseTypExpr p in
4582-
let () =
4583-
match p.token with
4584-
| Rbrace ->
4585-
(* {...x}, spread without extra fields *)
4586-
Parser.next p
4587-
| _ -> Parser.expect Comma p
4588-
in
4589-
let () =
4590-
match p.token with
4591-
| Lident _ ->
4592-
Parser.err ~startPos:dotdotdotStart ~endPos:dotdotdotEnd p
4593-
(Diagnostics.message ErrorMessages.spreadInRecordDeclaration)
4594-
| _ -> ()
4595-
in
4596-
let fields =
4597-
Parsetree.Oinherit typ
4598-
:: parseCommaDelimitedRegion
4599-
~grammar:Grammar.StringFieldDeclarations ~closing:Rbrace
4600-
~f:parseStringFieldDeclaration p
4601-
in
4602-
Parser.expect Rbrace p;
4603-
let loc = mkLoc startPos p.prevEndPos in
4604-
let typ =
4605-
Ast_helper.Typ.object_ ~loc fields Asttypes.Closed
4606-
|> parseTypeAlias p
4607-
in
4608-
let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in
4609-
Parser.optional p Comma |> ignore;
4610-
let moreArgs =
4611-
parseCommaDelimitedRegion ~grammar:Grammar.TypExprList
4612-
~closing:Rparen ~f:parseTypExprRegion p
4613-
in
4614-
Parser.expect Rparen p;
4615-
Parsetree.Pcstr_tuple (typ :: moreArgs)
4583+
(* always treat single spreads as records *)
4584+
let isSingleSpread = p.token = Rbrace in
4585+
if isSingleSpread then (
4586+
Parser.expect Rbrace p;
4587+
let loc = mkLoc startPos p.prevEndPos in
4588+
let dotField =
4589+
typ |> makeRecordDotField ~loc ~dotdotdotStart ~dotdotdotEnd
4590+
in
4591+
Parser.expect Rparen p;
4592+
Parsetree.Pcstr_record [dotField])
4593+
else
4594+
let fields =
4595+
Parsetree.Oinherit typ
4596+
:: parseCommaDelimitedRegion
4597+
~grammar:Grammar.StringFieldDeclarations ~closing:Rbrace
4598+
~f:parseStringFieldDeclaration p
4599+
in
4600+
Parser.expect Rbrace p;
4601+
let loc = mkLoc startPos p.prevEndPos in
4602+
let typ =
4603+
Ast_helper.Typ.object_ ~loc fields Asttypes.Closed
4604+
|> parseTypeAlias p
4605+
in
4606+
let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in
4607+
Parser.optional p Comma |> ignore;
4608+
let moreArgs =
4609+
parseCommaDelimitedRegion ~grammar:Grammar.TypExprList
4610+
~closing:Rparen ~f:parseTypExprRegion p
4611+
in
4612+
Parser.expect Rparen p;
4613+
Parsetree.Pcstr_tuple (typ :: moreArgs)
46164614
| _ -> (
46174615
let attrs = parseAttributes p in
46184616
match p.Parser.token with
@@ -5016,19 +5014,15 @@ and parseRecordOrObjectDecl p =
50165014
Parser.next p;
50175015
let loc = mkLoc startPos p.prevEndPos in
50185016
let dotField =
5019-
Ast_helper.Type.field ~loc
5020-
{txt = "..."; loc = mkLoc dotdotdotStart dotdotdotEnd}
5021-
typ
5017+
typ |> makeRecordDotField ~loc ~dotdotdotStart ~dotdotdotEnd
50225018
in
50235019
let kind = Parsetree.Ptype_record [dotField] in
50245020
(None, Public, kind)
50255021
| _ ->
50265022
Parser.expect Comma p;
50275023
let loc = mkLoc startPos p.prevEndPos in
50285024
let dotField =
5029-
Ast_helper.Type.field ~loc
5030-
{txt = "..."; loc = mkLoc dotdotdotStart dotdotdotEnd}
5031-
typ
5025+
typ |> makeRecordDotField ~loc ~dotdotdotStart ~dotdotdotEnd
50325026
in
50335027
let foundObjectField = ref false in
50345028
let fields =

jscomp/test/record_type_spread.js

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

jscomp/test/record_type_spread.res

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,7 @@ type base = {
6868
type inlineRecord = One({first: string, ...base})
6969

7070
let o = One({first: "1", id: "1"})
71+
72+
type inlineRecordSingleSpread = OneSingle({...base})
73+
74+
let o2 = OneSingle({id: "1"})

0 commit comments

Comments
 (0)