Skip to content

Commit 2f8d81b

Browse files
committedJan 11, 2025
allow inline records in constrs
1 parent d7f1437 commit 2f8d81b

File tree

5 files changed

+74
-39
lines changed

5 files changed

+74
-39
lines changed
 

‎compiler/syntax/src/res_core.ml

+34-9
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,15 @@ module ErrorMessages = struct
134134

135135
let forbidden_inline_record_declaration =
136136
"An inline record type declaration is only allowed in a variant \
137-
constructor's declaration"
137+
constructor's declaration or nested inside of a record type declaration"
138138

139139
let poly_var_int_with_suffix number =
140140
"A numeric polymorphic variant cannot be followed by a letter. Did you \
141141
mean `#" ^ number ^ "`?"
142+
143+
let multiple_inline_record_definitions_at_same_path =
144+
"Only one inline record definition is allowed per record field. This \
145+
defines more than one inline record."
142146
end
143147

144148
module InExternal = struct
@@ -4087,7 +4091,22 @@ and parse_atomic_typ_expr ?current_type_name_path ?inline_types ~attrs p =
40874091
| Lbracket -> parse_polymorphic_variant_type ~attrs p
40884092
| Uident _ | Lident _ ->
40894093
let constr = parse_value_path p in
4090-
let args = parse_type_constructor_args ~constr_name:constr p in
4094+
let args =
4095+
parse_type_constructor_args ?inline_types ?current_type_name_path
4096+
~constr_name:constr p
4097+
in
4098+
let number_of_inline_records_in_args =
4099+
args
4100+
|> List.filter (fun (c : Parsetree.core_type) ->
4101+
c.ptyp_attributes
4102+
|> List.exists (fun (({txt}, _) : Parsetree.attribute) ->
4103+
txt = "res.inlineRecordReference"))
4104+
|> List.length
4105+
in
4106+
if number_of_inline_records_in_args > 1 then
4107+
Parser.err ~start_pos ~end_pos:p.prev_end_pos p
4108+
(Diagnostics.message
4109+
ErrorMessages.multiple_inline_record_definitions_at_same_path);
40914110
Ast_helper.Typ.constr
40924111
~loc:(mk_loc start_pos p.prev_end_pos)
40934112
~attrs constr args
@@ -4194,7 +4213,7 @@ and parse_record_or_object_type ?current_type_name_path ?inline_types ~attrs p =
41944213

41954214
let lid = Location.mkloc (Longident.Lident inline_type_name) loc in
41964215
Ast_helper.Typ.constr
4197-
~attrs:[(Location.mknoloc "inlineRecordReference", PStr [])]
4216+
~attrs:[(Location.mknoloc "res.inlineRecordReference", PStr [])]
41984217
~loc lid []
41994218
| _ ->
42004219
let () =
@@ -4472,15 +4491,17 @@ and parse_tuple_type ~attrs ~first ~start_pos p =
44724491
let tuple_loc = mk_loc start_pos p.prev_end_pos in
44734492
Ast_helper.Typ.tuple ~attrs ~loc:tuple_loc typexprs
44744493

4475-
and parse_type_constructor_arg_region p =
4476-
if Grammar.is_typ_expr_start p.Parser.token then Some (parse_typ_expr p)
4494+
and parse_type_constructor_arg_region ?inline_types ?current_type_name_path p =
4495+
if Grammar.is_typ_expr_start p.Parser.token then
4496+
Some (parse_typ_expr ?inline_types ?current_type_name_path p)
44774497
else if p.token = LessThan then (
44784498
Parser.next p;
4479-
parse_type_constructor_arg_region p)
4499+
parse_type_constructor_arg_region ?inline_types ?current_type_name_path p)
44804500
else None
44814501

44824502
(* Js.Nullable.value<'a> *)
4483-
and parse_type_constructor_args ~constr_name p =
4503+
and parse_type_constructor_args ?inline_types ?current_type_name_path
4504+
~constr_name p =
44844505
let opening = p.Parser.token in
44854506
let opening_start_pos = p.start_pos in
44864507
match opening with
@@ -4490,7 +4511,11 @@ and parse_type_constructor_args ~constr_name p =
44904511
let type_args =
44914512
(* TODO: change Grammar.TypExprList to TypArgList!!! Why did I wrote this? *)
44924513
parse_comma_delimited_region ~grammar:Grammar.TypExprList
4493-
~closing:GreaterThan ~f:parse_type_constructor_arg_region p
4514+
~closing:GreaterThan
4515+
~f:
4516+
(parse_type_constructor_arg_region ?inline_types
4517+
?current_type_name_path)
4518+
p
44944519
in
44954520
let () =
44964521
match p.token with
@@ -5589,7 +5614,7 @@ and parse_type_definition_or_extension ~attrs p =
55895614
!inline_types
55905615
|> List.map (fun (inline_type_name, loc, kind) ->
55915616
Ast_helper.Type.mk
5592-
~attrs:[(Location.mknoloc "inlineRecordDefinition", PStr [])]
5617+
~attrs:[(Location.mknoloc "res.inlineRecordDefinition", PStr [])]
55935618
~loc ~kind
55945619
{name with txt = inline_type_name})
55955620
in

‎compiler/syntax/src/res_parsetree_viewer.ml

+6-3
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ let filter_parsing_attrs attrs =
204204
( "res.braces" | "ns.braces" | "res.iflet" | "res.namedArgLoc"
205205
| "res.ternary" | "res.await" | "res.template"
206206
| "res.taggedTemplate" | "res.patVariantSpread"
207-
| "res.dictPattern" );
207+
| "res.dictPattern" | "res.inlineRecordReference"
208+
| "res.inlineRecordDefinition" );
208209
},
209210
_ ) ->
210211
false
@@ -358,7 +359,8 @@ let has_attributes attrs =
358359
| ( {
359360
Location.txt =
360361
( "res.braces" | "ns.braces" | "res.iflet" | "res.ternary"
361-
| "res.await" | "res.template" );
362+
| "res.await" | "res.template" | "res.inlineRecordReference"
363+
| "res.inlineRecordDefinition" );
362364
},
363365
_ ) ->
364366
false
@@ -553,7 +555,8 @@ let is_printable_attribute attr =
553555
| ( {
554556
Location.txt =
555557
( "res.iflet" | "res.braces" | "ns.braces" | "JSX" | "res.await"
556-
| "res.template" | "res.ternary" );
558+
| "res.template" | "res.ternary" | "res.inlineRecordReference"
559+
| "res.inlineRecordDefinition" );
557560
},
558561
_ ) ->
559562
false

‎compiler/syntax/src/res_printer.ml

+26-27
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,12 @@ end
553553
let is_inline_record_definition attrs =
554554
attrs
555555
|> List.exists (fun (({txt}, _) : Parsetree.attribute) ->
556-
txt = "inlineRecordDefinition")
556+
txt = "res.inlineRecordDefinition")
557557

558558
let is_inline_record_reference attrs =
559559
attrs
560560
|> List.exists (fun (({txt}, _) : Parsetree.attribute) ->
561-
txt = "inlineRecordReference")
561+
txt = "res.inlineRecordReference")
562562

563563
let rec print_structure ~state (s : Parsetree.structure) t =
564564
match s with
@@ -587,9 +587,7 @@ and print_structure_item ~state (si : Parsetree.structure_item) cmt_tbl =
587587
let inline_record_definitions, regular_declarations =
588588
type_declarations
589589
|> List.partition (fun (td : Parsetree.type_declaration) ->
590-
td.ptype_attributes
591-
|> List.exists (fun (({txt}, _) : Parsetree.attribute) ->
592-
txt = "inlineRecordDefinition"))
590+
is_inline_record_definition td.ptype_attributes)
593591
in
594592
print_type_declarations ~inline_record_definitions ~state
595593
~rec_flag:
@@ -1616,28 +1614,11 @@ and print_label_declaration ?inline_record_definitions ~state
16161614
name;
16171615
optional;
16181616
(if is_dot then Doc.nil else Doc.text ": ");
1619-
(match
1620-
( inline_record_definitions,
1621-
is_inline_record_reference ld.pld_type.ptyp_attributes,
1622-
ld.pld_type )
1623-
with
1624-
| ( Some inline_record_definitions,
1625-
true,
1626-
{ptyp_desc = Ptyp_constr ({txt = Lident constr_name}, _)} ) -> (
1627-
let record_definition =
1628-
inline_record_definitions
1629-
|> List.find_opt (fun (r : Parsetree.type_declaration) ->
1630-
r.ptype_name.txt = constr_name)
1631-
in
1632-
match record_definition with
1633-
| Some {ptype_kind = Ptype_record lds} ->
1634-
print_record_declaration ~inline_record_definitions ~state lds
1635-
cmt_tbl
1636-
| _ -> assert false)
1637-
| _ -> print_typ_expr ~state ld.pld_type cmt_tbl);
1617+
print_typ_expr ?inline_record_definitions ~state ld.pld_type cmt_tbl;
16381618
])
16391619

1640-
and print_typ_expr ~(state : State.t) (typ_expr : Parsetree.core_type) cmt_tbl =
1620+
and print_typ_expr ?inline_record_definitions ~(state : State.t)
1621+
(typ_expr : Parsetree.core_type) cmt_tbl =
16411622
let print_arrow ~arity typ_expr =
16421623
let max_arity =
16431624
match arity with
@@ -1742,6 +1723,22 @@ and print_typ_expr ~(state : State.t) (typ_expr : Parsetree.core_type) cmt_tbl =
17421723
| Ptyp_object (fields, open_flag) ->
17431724
print_object ~state ~inline:false fields open_flag cmt_tbl
17441725
| Ptyp_arrow (_, _, _, arity) -> print_arrow ~arity typ_expr
1726+
| Ptyp_constr ({txt = Lident inline_record_name}, [])
1727+
when is_inline_record_reference typ_expr.ptyp_attributes -> (
1728+
let inline_record_definitions =
1729+
match inline_record_definitions with
1730+
| None -> []
1731+
| Some v -> v
1732+
in
1733+
let record_definition =
1734+
inline_record_definitions
1735+
|> List.find_opt (fun (r : Parsetree.type_declaration) ->
1736+
r.ptype_name.txt = inline_record_name)
1737+
in
1738+
match record_definition with
1739+
| Some {ptype_kind = Ptype_record lds} ->
1740+
print_record_declaration ~inline_record_definitions ~state lds cmt_tbl
1741+
| _ -> assert false)
17451742
| Ptyp_constr
17461743
(longident_loc, [{ptyp_desc = Ptyp_object (fields, open_flag)}]) ->
17471744
(* for foo<{"a": b}>, when the object is long and needs a line break, we
@@ -1782,15 +1779,17 @@ and print_typ_expr ~(state : State.t) (typ_expr : Parsetree.core_type) cmt_tbl =
17821779
~sep:(Doc.concat [Doc.comma; Doc.line])
17831780
(List.map
17841781
(fun typexpr ->
1785-
print_typ_expr ~state typexpr cmt_tbl)
1782+
print_typ_expr ?inline_record_definitions ~state
1783+
typexpr cmt_tbl)
17861784
constr_args);
17871785
]);
17881786
Doc.trailing_comma;
17891787
Doc.soft_line;
17901788
Doc.greater_than;
17911789
]))
17921790
| Ptyp_tuple types -> print_tuple_type ~state ~inline:false types cmt_tbl
1793-
| Ptyp_poly ([], typ) -> print_typ_expr ~state typ cmt_tbl
1791+
| Ptyp_poly ([], typ) ->
1792+
print_typ_expr ?inline_record_definitions ~state typ cmt_tbl
17941793
| Ptyp_poly (string_locs, typ) ->
17951794
Doc.concat
17961795
[

‎tests/tests/src/nested_records.mjs

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ let options = {
66
name: "test",
77
superExtra: {
88
age: 2222
9+
},
10+
otherExtra: {
11+
test: true,
12+
anotherInlined: {
13+
record: true
14+
}
915
}
1016
}
1117
};

‎tests/tests/src/nested_records.res

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ type options = {
22
extra?: {
33
name: string,
44
superExtra?: {age: int},
5+
otherExtra: option<{test: bool, anotherInlined: {record: bool}}>,
56
},
67
}
78

@@ -11,5 +12,6 @@ let options = {
1112
superExtra: {
1213
age: 2222,
1314
},
15+
otherExtra: Some({test: true, anotherInlined: {record: true}}),
1416
},
1517
}

0 commit comments

Comments
 (0)