Skip to content

Commit 10634fe

Browse files
committed
allow inline records in constrs
1 parent f962dd0 commit 10634fe

File tree

5 files changed

+74
-39
lines changed

5 files changed

+74
-39
lines changed

compiler/syntax/src/res_core.ml

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,15 @@ module ErrorMessages = struct
141141

142142
let forbidden_inline_record_declaration =
143143
"An inline record type declaration is only allowed in a variant \
144-
constructor's declaration"
144+
constructor's declaration or nested inside of a record type declaration"
145145

146146
let poly_var_int_with_suffix number =
147147
"A numeric polymorphic variant cannot be followed by a letter. Did you \
148148
mean `#" ^ number ^ "`?"
149+
150+
let multiple_inline_record_definitions_at_same_path =
151+
"Only one inline record definition is allowed per record field. This \
152+
defines more than one inline record."
149153
end
150154

151155
module InExternal = struct
@@ -4146,7 +4150,22 @@ and parse_atomic_typ_expr ?current_type_name_path ?inline_types ~attrs p =
41464150
| Lbracket -> parse_polymorphic_variant_type ~attrs p
41474151
| Uident _ | Lident _ ->
41484152
let constr = parse_value_path p in
4149-
let args = parse_type_constructor_args ~constr_name:constr p in
4153+
let args =
4154+
parse_type_constructor_args ?inline_types ?current_type_name_path
4155+
~constr_name:constr p
4156+
in
4157+
let number_of_inline_records_in_args =
4158+
args
4159+
|> List.filter (fun (c : Parsetree.core_type) ->
4160+
c.ptyp_attributes
4161+
|> List.exists (fun (({txt}, _) : Parsetree.attribute) ->
4162+
txt = "res.inlineRecordReference"))
4163+
|> List.length
4164+
in
4165+
if number_of_inline_records_in_args > 1 then
4166+
Parser.err ~start_pos ~end_pos:p.prev_end_pos p
4167+
(Diagnostics.message
4168+
ErrorMessages.multiple_inline_record_definitions_at_same_path);
41504169
Ast_helper.Typ.constr
41514170
~loc:(mk_loc start_pos p.prev_end_pos)
41524171
~attrs constr args
@@ -4253,7 +4272,7 @@ and parse_record_or_object_type ?current_type_name_path ?inline_types ~attrs p =
42534272

42544273
let lid = Location.mkloc (Longident.Lident inline_type_name) loc in
42554274
Ast_helper.Typ.constr
4256-
~attrs:[(Location.mknoloc "inlineRecordReference", PStr [])]
4275+
~attrs:[(Location.mknoloc "res.inlineRecordReference", PStr [])]
42574276
~loc lid []
42584277
| _ ->
42594278
let () =
@@ -4531,15 +4550,17 @@ and parse_tuple_type ~attrs ~first ~start_pos p =
45314550
let tuple_loc = mk_loc start_pos p.prev_end_pos in
45324551
Ast_helper.Typ.tuple ~attrs ~loc:tuple_loc typexprs
45334552

4534-
and parse_type_constructor_arg_region p =
4535-
if Grammar.is_typ_expr_start p.Parser.token then Some (parse_typ_expr p)
4553+
and parse_type_constructor_arg_region ?inline_types ?current_type_name_path p =
4554+
if Grammar.is_typ_expr_start p.Parser.token then
4555+
Some (parse_typ_expr ?inline_types ?current_type_name_path p)
45364556
else if p.token = LessThan then (
45374557
Parser.next p;
4538-
parse_type_constructor_arg_region p)
4558+
parse_type_constructor_arg_region ?inline_types ?current_type_name_path p)
45394559
else None
45404560

45414561
(* Js.Nullable.value<'a> *)
4542-
and parse_type_constructor_args ~constr_name p =
4562+
and parse_type_constructor_args ?inline_types ?current_type_name_path
4563+
~constr_name p =
45434564
let opening = p.Parser.token in
45444565
let opening_start_pos = p.start_pos in
45454566
match opening with
@@ -4549,7 +4570,11 @@ and parse_type_constructor_args ~constr_name p =
45494570
let type_args =
45504571
(* TODO: change Grammar.TypExprList to TypArgList!!! Why did I wrote this? *)
45514572
parse_comma_delimited_region ~grammar:Grammar.TypExprList
4552-
~closing:GreaterThan ~f:parse_type_constructor_arg_region p
4573+
~closing:GreaterThan
4574+
~f:
4575+
(parse_type_constructor_arg_region ?inline_types
4576+
?current_type_name_path)
4577+
p
45534578
in
45544579
let () =
45554580
match p.token with
@@ -5648,7 +5673,7 @@ and parse_type_definition_or_extension ~attrs p =
56485673
!inline_types
56495674
|> List.map (fun (inline_type_name, loc, kind) ->
56505675
Ast_helper.Type.mk
5651-
~attrs:[(Location.mknoloc "inlineRecordDefinition", PStr [])]
5676+
~attrs:[(Location.mknoloc "res.inlineRecordDefinition", PStr [])]
56525677
~loc ~kind
56535678
{name with txt = inline_type_name})
56545679
in

compiler/syntax/src/res_parsetree_viewer.ml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ let filter_parsing_attrs attrs =
247247
( "res.braces" | "ns.braces" | "res.iflet" | "res.namedArgLoc"
248248
| "res.ternary" | "res.async" | "res.await" | "res.template"
249249
| "res.taggedTemplate" | "res.patVariantSpread"
250-
| "res.dictPattern" );
250+
| "res.dictPattern" | "res.inlineRecordReference"
251+
| "res.inlineRecordDefinition" );
251252
},
252253
_ ) ->
253254
false
@@ -396,7 +397,8 @@ let has_attributes attrs =
396397
| ( {
397398
Location.txt =
398399
( "res.braces" | "ns.braces" | "res.iflet" | "res.ternary"
399-
| "res.async" | "res.await" | "res.template" );
400+
| "res.async" | "res.await" | "res.template"
401+
| "res.inlineRecordReference" | "res.inlineRecordDefinition" );
400402
},
401403
_ ) ->
402404
false
@@ -580,7 +582,8 @@ let is_printable_attribute attr =
580582
| ( {
581583
Location.txt =
582584
( "res.iflet" | "res.braces" | "ns.braces" | "JSX" | "res.async"
583-
| "res.await" | "res.template" | "res.ternary" );
585+
| "res.await" | "res.template" | "res.ternary"
586+
| "res.inlineRecordReference" | "res.inlineRecordDefinition" );
584587
},
585588
_ ) ->
586589
false

compiler/syntax/src/res_printer.ml

Lines changed: 26 additions & 27 deletions
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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)