Skip to content

Commit 3a89ab3

Browse files
committed
allow inline records in constrs
1 parent 3dcf300 commit 3a89ab3

File tree

5 files changed

+72
-38
lines changed

5 files changed

+72
-38
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
@@ -4071,7 +4075,22 @@ and parse_atomic_typ_expr ?current_type_name_path ?inline_types ~attrs p =
40714075
| Lbracket -> parse_polymorphic_variant_type ~attrs p
40724076
| Uident _ | Lident _ ->
40734077
let constr = parse_value_path p in
4074-
let args = parse_type_constructor_args ~constr_name:constr p in
4078+
let args =
4079+
parse_type_constructor_args ?inline_types ?current_type_name_path
4080+
~constr_name:constr p
4081+
in
4082+
let number_of_inline_records_in_args =
4083+
args
4084+
|> List.filter (fun (c : Parsetree.core_type) ->
4085+
c.ptyp_attributes
4086+
|> List.exists (fun (({txt}, _) : Parsetree.attribute) ->
4087+
txt = "res.inlineRecordReference"))
4088+
|> List.length
4089+
in
4090+
if number_of_inline_records_in_args > 1 then
4091+
Parser.err ~start_pos ~end_pos:p.prev_end_pos p
4092+
(Diagnostics.message
4093+
ErrorMessages.multiple_inline_record_definitions_at_same_path);
40754094
Ast_helper.Typ.constr
40764095
~loc:(mk_loc start_pos p.prev_end_pos)
40774096
~attrs constr args
@@ -4178,7 +4197,7 @@ and parse_record_or_object_type ?current_type_name_path ?inline_types ~attrs p =
41784197

41794198
let lid = Location.mkloc (Longident.Lident inline_type_name) loc in
41804199
Ast_helper.Typ.constr
4181-
~attrs:[(Location.mknoloc "inlineRecordReference", PStr [])]
4200+
~attrs:[(Location.mknoloc "res.inlineRecordReference", PStr [])]
41824201
~loc lid []
41834202
| _ ->
41844203
let () =
@@ -4447,15 +4466,17 @@ and parse_tuple_type ~attrs ~first ~start_pos p =
44474466
let tuple_loc = mk_loc start_pos p.prev_end_pos in
44484467
Ast_helper.Typ.tuple ~attrs ~loc:tuple_loc typexprs
44494468

4450-
and parse_type_constructor_arg_region p =
4451-
if Grammar.is_typ_expr_start p.Parser.token then Some (parse_typ_expr p)
4469+
and parse_type_constructor_arg_region ?inline_types ?current_type_name_path p =
4470+
if Grammar.is_typ_expr_start p.Parser.token then
4471+
Some (parse_typ_expr ?inline_types ?current_type_name_path p)
44524472
else if p.token = LessThan then (
44534473
Parser.next p;
4454-
parse_type_constructor_arg_region p)
4474+
parse_type_constructor_arg_region ?inline_types ?current_type_name_path p)
44554475
else None
44564476

44574477
(* Js.Nullable.value<'a> *)
4458-
and parse_type_constructor_args ~constr_name p =
4478+
and parse_type_constructor_args ?inline_types ?current_type_name_path
4479+
~constr_name p =
44594480
let opening = p.Parser.token in
44604481
let opening_start_pos = p.start_pos in
44614482
match opening with
@@ -4465,7 +4486,11 @@ and parse_type_constructor_args ~constr_name p =
44654486
let type_args =
44664487
(* TODO: change Grammar.TypExprList to TypArgList!!! Why did I wrote this? *)
44674488
parse_comma_delimited_region ~grammar:Grammar.TypExprList
4468-
~closing:GreaterThan ~f:parse_type_constructor_arg_region p
4489+
~closing:GreaterThan
4490+
~f:
4491+
(parse_type_constructor_arg_region ?inline_types
4492+
?current_type_name_path)
4493+
p
44694494
in
44704495
let () =
44714496
match p.token with
@@ -5563,7 +5588,7 @@ and parse_type_definition_or_extension ~attrs p =
55635588
!inline_types
55645589
|> List.map (fun (inline_type_name, loc, kind) ->
55655590
Ast_helper.Type.mk
5566-
~attrs:[(Location.mknoloc "inlineRecordDefinition", PStr [])]
5591+
~attrs:[(Location.mknoloc "res.inlineRecordDefinition", PStr [])]
55675592
~loc ~kind
55685593
{name with txt = inline_type_name})
55695594
in

compiler/syntax/src/res_parsetree_viewer.ml

+4-2
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ let has_attributes attrs =
352352
| ( {
353353
Location.txt =
354354
( "res.braces" | "ns.braces" | "res.iflet" | "res.ternary"
355-
| "res.await" | "res.template" );
355+
| "res.await" | "res.template" | "res.inlineRecordReference"
356+
| "res.inlineRecordDefinition" );
356357
},
357358
_ ) ->
358359
false
@@ -547,7 +548,8 @@ let is_printable_attribute attr =
547548
| ( {
548549
Location.txt =
549550
( "res.iflet" | "res.braces" | "ns.braces" | "JSX" | "res.await"
550-
| "res.template" | "res.ternary" );
551+
| "res.template" | "res.ternary" | "res.inlineRecordReference"
552+
| "res.inlineRecordDefinition" );
551553
},
552554
_ ) ->
553555
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:
@@ -1614,28 +1612,11 @@ and print_label_declaration ?inline_record_definitions ~state
16141612
name;
16151613
optional;
16161614
(if is_dot then Doc.nil else Doc.text ": ");
1617-
(match
1618-
( inline_record_definitions,
1619-
is_inline_record_reference ld.pld_type.ptyp_attributes,
1620-
ld.pld_type )
1621-
with
1622-
| ( Some inline_record_definitions,
1623-
true,
1624-
{ptyp_desc = Ptyp_constr ({txt = Lident constr_name}, _)} ) -> (
1625-
let record_definition =
1626-
inline_record_definitions
1627-
|> List.find_opt (fun (r : Parsetree.type_declaration) ->
1628-
r.ptype_name.txt = constr_name)
1629-
in
1630-
match record_definition with
1631-
| Some {ptype_kind = Ptype_record lds} ->
1632-
print_record_declaration ~inline_record_definitions ~state lds
1633-
cmt_tbl
1634-
| _ -> assert false)
1635-
| _ -> print_typ_expr ~state ld.pld_type cmt_tbl);
1615+
print_typ_expr ?inline_record_definitions ~state ld.pld_type cmt_tbl;
16361616
])
16371617

1638-
and print_typ_expr ~(state : State.t) (typ_expr : Parsetree.core_type) cmt_tbl =
1618+
and print_typ_expr ?inline_record_definitions ~(state : State.t)
1619+
(typ_expr : Parsetree.core_type) cmt_tbl =
16391620
let print_arrow ~arity typ_expr =
16401621
let max_arity =
16411622
match arity with
@@ -1740,6 +1721,22 @@ and print_typ_expr ~(state : State.t) (typ_expr : Parsetree.core_type) cmt_tbl =
17401721
| Ptyp_object (fields, open_flag) ->
17411722
print_object ~state ~inline:false fields open_flag cmt_tbl
17421723
| Ptyp_arrow {arity} -> print_arrow ~arity typ_expr
1724+
| Ptyp_constr ({txt = Lident inline_record_name}, [])
1725+
when is_inline_record_reference typ_expr.ptyp_attributes -> (
1726+
let inline_record_definitions =
1727+
match inline_record_definitions with
1728+
| None -> []
1729+
| Some v -> v
1730+
in
1731+
let record_definition =
1732+
inline_record_definitions
1733+
|> List.find_opt (fun (r : Parsetree.type_declaration) ->
1734+
r.ptype_name.txt = inline_record_name)
1735+
in
1736+
match record_definition with
1737+
| Some {ptype_kind = Ptype_record lds} ->
1738+
print_record_declaration ~inline_record_definitions ~state lds cmt_tbl
1739+
| _ -> assert false)
17431740
| Ptyp_constr
17441741
(longident_loc, [{ptyp_desc = Ptyp_object (fields, open_flag)}]) ->
17451742
(* for foo<{"a": b}>, when the object is long and needs a line break, we
@@ -1780,15 +1777,17 @@ and print_typ_expr ~(state : State.t) (typ_expr : Parsetree.core_type) cmt_tbl =
17801777
~sep:(Doc.concat [Doc.comma; Doc.line])
17811778
(List.map
17821779
(fun typexpr ->
1783-
print_typ_expr ~state typexpr cmt_tbl)
1780+
print_typ_expr ?inline_record_definitions ~state
1781+
typexpr cmt_tbl)
17841782
constr_args);
17851783
]);
17861784
Doc.trailing_comma;
17871785
Doc.soft_line;
17881786
Doc.greater_than;
17891787
]))
17901788
| Ptyp_tuple types -> print_tuple_type ~state ~inline:false types cmt_tbl
1791-
| Ptyp_poly ([], typ) -> print_typ_expr ~state typ cmt_tbl
1789+
| Ptyp_poly ([], typ) ->
1790+
print_typ_expr ?inline_record_definitions ~state typ cmt_tbl
17921791
| Ptyp_poly (string_locs, typ) ->
17931792
Doc.concat
17941793
[

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)