Skip to content

Commit 1410016

Browse files
committed
AST: always put type parameters first in function definitions.
Normalize function definitions to be of the form `(type a b c, x, y) => ...`, moving all the types first if they are not already.
1 parent c0f430a commit 1410016

File tree

7 files changed

+150
-132
lines changed

7 files changed

+150
-132
lines changed

compiler/syntax/src/res_core.ml

+124-92
Original file line numberDiff line numberDiff line change
@@ -182,26 +182,53 @@ type typ_def_or_ext =
182182
}
183183
| TypeExt of Parsetree.type_extension
184184

185-
type labelled_parameter =
186-
| TermParameter of {
187-
attrs: Parsetree.attributes;
188-
label: Asttypes.arg_label;
189-
expr: Parsetree.expression option;
190-
pat: Parsetree.pattern;
191-
pos: Lexing.position;
192-
}
193-
| TypeParameter of {
194-
attrs: Parsetree.attributes;
195-
locs: string Location.loc list;
196-
pos: Lexing.position;
197-
}
185+
type fundef_type_param = {
186+
attrs: Parsetree.attributes;
187+
locs: string Location.loc list;
188+
p_pos: Lexing.position;
189+
}
190+
191+
type fundef_term_param = {
192+
attrs: Parsetree.attributes;
193+
p_label: Asttypes.arg_label;
194+
expr: Parsetree.expression option;
195+
pat: Parsetree.pattern;
196+
p_pos: Lexing.position;
197+
}
198+
199+
(* Single parameter of a function definition (type a b, x, ~y) *)
200+
type fundef_parameter =
201+
| TermParameter of fundef_term_param
202+
| TypeParameter of fundef_type_param
198203

199204
type record_pattern_item =
200205
| PatUnderscore
201206
| PatField of (Ast_helper.lid * Parsetree.pattern * bool (* optional *))
202207

203208
type context = OrdinaryExpr | TernaryTrueBranchExpr | WhenExpr
204209

210+
(* Extracts type and term parameters from a list of function definition parameters, combining all type parameters into one *)
211+
let rec extract_fundef_params ~(type_acc : fundef_type_param option)
212+
~(term_acc : fundef_term_param list) (params : fundef_parameter list) :
213+
fundef_type_param option * fundef_term_param list =
214+
match params with
215+
| TermParameter tp :: rest ->
216+
extract_fundef_params ~type_acc ~term_acc:(tp :: term_acc) rest
217+
| TypeParameter tp :: rest ->
218+
let type_acc =
219+
match type_acc with
220+
| Some tpa ->
221+
Some
222+
{
223+
attrs = tpa.attrs @ tp.attrs;
224+
locs = tpa.locs @ tp.locs;
225+
p_pos = tpa.p_pos;
226+
}
227+
| None -> Some tp
228+
in
229+
extract_fundef_params ~type_acc ~term_acc rest
230+
| [] -> (type_acc, List.rev term_acc)
231+
205232
let get_closing_token = function
206233
| Token.Lparen -> Token.Rparen
207234
| Lbrace -> Rbrace
@@ -1510,7 +1537,7 @@ and parse_ternary_expr left_operand p =
15101537
| _ -> left_operand
15111538

15121539
and parse_es6_arrow_expression ?(arrow_attrs = []) ?(arrow_start_pos = None)
1513-
?context ?parameters p =
1540+
?context ?term_parameters p =
15141541
let start_pos = p.Parser.start_pos in
15151542
Parser.leave_breadcrumb p Grammar.Es6ArrowExpr;
15161543
(* Parsing function parameters and attributes:
@@ -1520,8 +1547,8 @@ and parse_es6_arrow_expression ?(arrow_attrs = []) ?(arrow_start_pos = None)
15201547
2. Attributes inside `(...)` are added to the arguments regardless of whether
15211548
labeled, optional or nolabeled *)
15221549
let parameters =
1523-
match parameters with
1524-
| Some params -> params
1550+
match term_parameters with
1551+
| Some params -> (None, params)
15251552
| None -> parse_parameters p
15261553
in
15271554
let parameters =
@@ -1532,15 +1559,23 @@ and parse_es6_arrow_expression ?(arrow_attrs = []) ?(arrow_start_pos = None)
15321559
| None -> pos
15331560
in
15341561
match parameters with
1535-
| TermParameter p :: rest ->
1536-
TermParameter
1537-
{p with attrs = update_attrs p.attrs; pos = update_pos p.pos}
1538-
:: rest
1539-
| TypeParameter p :: rest ->
1540-
TypeParameter
1541-
{p with attrs = update_attrs p.attrs; pos = update_pos p.pos}
1542-
:: rest
1543-
| [] -> parameters
1562+
| None, termp :: rest ->
1563+
( None,
1564+
{
1565+
termp with
1566+
attrs = update_attrs termp.attrs;
1567+
p_pos = update_pos termp.p_pos;
1568+
}
1569+
:: rest )
1570+
| Some (tpa : fundef_type_param), term_params ->
1571+
( Some
1572+
{
1573+
tpa with
1574+
attrs = update_attrs tpa.attrs;
1575+
p_pos = update_pos tpa.p_pos;
1576+
},
1577+
term_params )
1578+
| _ -> parameters
15441579
in
15451580
let return_type =
15461581
match p.Parser.token with
@@ -1561,32 +1596,32 @@ and parse_es6_arrow_expression ?(arrow_attrs = []) ?(arrow_start_pos = None)
15611596
in
15621597
Parser.eat_breadcrumb p;
15631598
let end_pos = p.prev_end_pos in
1564-
let term_parameters =
1565-
parameters
1566-
|> List.filter (function
1567-
| TermParameter _ -> true
1568-
| TypeParameter _ -> false)
1569-
in
1570-
let _paramNum, arrow_expr, _arity =
1599+
let type_param_opt, term_parameters = parameters in
1600+
let _paramNum, arrow_expr =
15711601
List.fold_right
1572-
(fun parameter (term_param_num, expr, arity) ->
1573-
match parameter with
1574-
| TermParameter
1575-
{attrs; label = lbl; expr = default_expr; pat; pos = start_pos} ->
1576-
let loc = mk_loc start_pos end_pos in
1577-
let fun_expr =
1578-
Ast_helper.Exp.fun_ ~loc ~attrs ~arity:None lbl default_expr pat
1579-
expr
1580-
in
1581-
if term_param_num = 1 then
1582-
(term_param_num - 1, Ast_uncurried.uncurried_fun ~arity fun_expr, 1)
1583-
else (term_param_num - 1, fun_expr, arity + 1)
1584-
| TypeParameter {attrs; locs = newtypes; pos = start_pos} ->
1585-
( term_param_num,
1586-
make_newtypes ~attrs ~loc:(mk_loc start_pos end_pos) newtypes expr,
1587-
arity ))
1588-
parameters
1589-
(List.length term_parameters, body, 1)
1602+
(fun parameter (term_param_num, expr) ->
1603+
let {attrs; p_label = lbl; expr = default_expr; pat; p_pos = start_pos}
1604+
=
1605+
parameter
1606+
in
1607+
let loc = mk_loc start_pos end_pos in
1608+
let fun_expr =
1609+
Ast_helper.Exp.fun_ ~loc ~attrs ~arity:None lbl default_expr pat expr
1610+
in
1611+
if term_param_num = 1 then
1612+
( term_param_num - 1,
1613+
Ast_uncurried.uncurried_fun
1614+
~arity:(List.length term_parameters)
1615+
fun_expr )
1616+
else (term_param_num - 1, fun_expr))
1617+
term_parameters
1618+
(List.length term_parameters, body)
1619+
in
1620+
let arrow_expr =
1621+
match type_param_opt with
1622+
| None -> arrow_expr
1623+
| Some {attrs; locs = newtypes; p_pos = start_pos} ->
1624+
make_newtypes ~attrs ~loc:(mk_loc start_pos end_pos) newtypes arrow_expr
15901625
in
15911626
{arrow_expr with pexp_loc = {arrow_expr.pexp_loc with loc_start = start_pos}}
15921627

@@ -1620,7 +1655,7 @@ and parse_parameter p =
16201655
if p.Parser.token = Typ then (
16211656
Parser.next p;
16221657
let lidents = parse_lident_list p in
1623-
Some (TypeParameter {attrs; locs = lidents; pos = start_pos}))
1658+
Some (TypeParameter {attrs; locs = lidents; p_pos = start_pos}))
16241659
else
16251660
let attrs, lbl, pat =
16261661
match p.Parser.token with
@@ -1694,15 +1729,17 @@ and parse_parameter p =
16941729
Parser.next p;
16951730
Some
16961731
(TermParameter
1697-
{attrs; label = lbl; expr = None; pat; pos = start_pos})
1732+
{attrs; p_label = lbl; expr = None; pat; p_pos = start_pos})
16981733
| _ ->
16991734
let expr = parse_constrained_or_coerced_expr p in
17001735
Some
17011736
(TermParameter
1702-
{attrs; label = lbl; expr = Some expr; pat; pos = start_pos}))
1737+
{attrs; p_label = lbl; expr = Some expr; pat; p_pos = start_pos})
1738+
)
17031739
| _ ->
17041740
Some
1705-
(TermParameter {attrs; label = lbl; expr = None; pat; pos = start_pos})
1741+
(TermParameter
1742+
{attrs; p_label = lbl; expr = None; pat; p_pos = start_pos})
17061743
else None
17071744

17081745
and parse_parameter_list p =
@@ -1711,12 +1748,7 @@ and parse_parameter_list p =
17111748
~f:parse_parameter ~closing:Rparen p
17121749
in
17131750
Parser.expect Rparen p;
1714-
let has_term_parameter =
1715-
Ext_list.exists parameters (function
1716-
| TermParameter _ -> true
1717-
| _ -> false)
1718-
in
1719-
(has_term_parameter, parameters)
1751+
extract_fundef_params ~type_acc:None ~term_acc:[] parameters
17201752

17211753
(* parameters ::=
17221754
* | _
@@ -1725,7 +1757,7 @@ and parse_parameter_list p =
17251757
* | (.)
17261758
* | ( parameter {, parameter} [,] )
17271759
*)
1728-
and parse_parameters p =
1760+
and parse_parameters p : fundef_type_param option * fundef_term_param list =
17291761
let start_pos = p.Parser.start_pos in
17301762
let unit_term_parameter () =
17311763
let loc = mk_loc start_pos p.Parser.prev_end_pos in
@@ -1734,51 +1766,52 @@ and parse_parameters p =
17341766
(Location.mkloc (Longident.Lident "()") loc)
17351767
None
17361768
in
1737-
TermParameter
1738-
{
1739-
attrs = [];
1740-
label = Asttypes.Nolabel;
1741-
expr = None;
1742-
pat = unit_pattern;
1743-
pos = start_pos;
1744-
}
1769+
{
1770+
attrs = [];
1771+
p_label = Asttypes.Nolabel;
1772+
expr = None;
1773+
pat = unit_pattern;
1774+
p_pos = start_pos;
1775+
}
17451776
in
17461777
match p.Parser.token with
17471778
| Lident ident ->
17481779
Parser.next p;
17491780
let loc = mk_loc start_pos p.Parser.prev_end_pos in
1750-
[
1751-
TermParameter
1781+
( None,
1782+
[
17521783
{
17531784
attrs = [];
1754-
label = Asttypes.Nolabel;
1785+
p_label = Asttypes.Nolabel;
17551786
expr = None;
17561787
pat = Ast_helper.Pat.var ~loc (Location.mkloc ident loc);
1757-
pos = start_pos;
1788+
p_pos = start_pos;
17581789
};
1759-
]
1790+
] )
17601791
| Underscore ->
17611792
Parser.next p;
17621793
let loc = mk_loc start_pos p.Parser.prev_end_pos in
1763-
[
1764-
TermParameter
1794+
( None,
1795+
[
17651796
{
17661797
attrs = [];
1767-
label = Asttypes.Nolabel;
1798+
p_label = Asttypes.Nolabel;
17681799
expr = None;
17691800
pat = Ast_helper.Pat.any ~loc ();
1770-
pos = start_pos;
1801+
p_pos = start_pos;
17711802
};
1772-
]
1803+
] )
17731804
| Lparen ->
17741805
Parser.next p;
17751806
ignore (Parser.optional p Dot);
1776-
let has_term_parameter, parameters = parse_parameter_list p in
1777-
if has_term_parameter then parameters
1778-
else parameters @ [unit_term_parameter ()]
1807+
let type_params, term_params = parse_parameter_list p in
1808+
let term_params =
1809+
if term_params <> [] then term_params else [unit_term_parameter ()]
1810+
in
1811+
(type_params, term_params)
17791812
| token ->
17801813
Parser.err p (Diagnostics.unexpected token p.breadcrumbs);
1781-
[]
1814+
(None, [])
17821815

17831816
and parse_coerced_expr ~(expr : Parsetree.expression) p =
17841817
Parser.expect ColonGreaterThan p;
@@ -2974,16 +3007,15 @@ and parse_braced_or_record_expr p =
29743007
let ident = Location.mkloc (Longident.last path_ident.txt) loc in
29753008
let a =
29763009
parse_es6_arrow_expression
2977-
~parameters:
3010+
~term_parameters:
29783011
[
2979-
TermParameter
2980-
{
2981-
attrs = [];
2982-
label = Asttypes.Nolabel;
2983-
expr = None;
2984-
pat = Ast_helper.Pat.var ~loc:ident.loc ident;
2985-
pos = start_pos;
2986-
};
3012+
{
3013+
attrs = [];
3014+
p_label = Asttypes.Nolabel;
3015+
expr = None;
3016+
pat = Ast_helper.Pat.var ~loc:ident.loc ident;
3017+
p_pos = start_pos;
3018+
};
29873019
]
29883020
p
29893021
in

compiler/syntax/src/res_parsetree_viewer.ml

-11
Original file line numberDiff line numberDiff line change
@@ -86,17 +86,6 @@ let has_partial_attribute attrs =
8686
| _ -> false)
8787
attrs
8888

89-
type function_attributes_info = {async: bool; attributes: Parsetree.attributes}
90-
91-
let process_function_attributes attrs =
92-
let rec process async acc attrs =
93-
match attrs with
94-
| [] -> {async; attributes = List.rev acc}
95-
| ({Location.txt = "res.async"}, _) :: rest -> process true acc rest
96-
| attr :: rest -> process async (attr :: acc) rest
97-
in
98-
process false [] attrs
99-
10089
let has_await_attribute attrs =
10190
List.exists
10291
(function

compiler/syntax/src/res_printer.ml

+2-6
Original file line numberDiff line numberDiff line change
@@ -2697,9 +2697,7 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl =
26972697
let print_arrow e =
26982698
let parameters, return_expr = ParsetreeViewer.fun_expr e in
26992699
let attrs_on_arrow = e.pexp_attributes in
2700-
let ParsetreeViewer.{async; attributes = attrs} =
2701-
ParsetreeViewer.process_function_attributes attrs_on_arrow
2702-
in
2700+
let async, attrs = Ast_async.extract_async_attribute attrs_on_arrow in
27032701
let return_expr, typ_constraint =
27042702
match return_expr.pexp_desc with
27052703
| Pexp_constraint (expr, typ) ->
@@ -3441,9 +3439,7 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl =
34413439
and print_pexp_fun ~state ~in_callback e cmt_tbl =
34423440
let parameters, return_expr = ParsetreeViewer.fun_expr e in
34433441
let attrs_on_arrow = e.pexp_attributes in
3444-
let ParsetreeViewer.{async; attributes = attrs} =
3445-
ParsetreeViewer.process_function_attributes attrs_on_arrow
3446-
in
3442+
let async, attrs = Ast_async.extract_async_attribute attrs_on_arrow in
34473443
let return_expr, typ_constraint =
34483444
match return_expr.pexp_desc with
34493445
| Pexp_constraint (expr, typ) ->

tests/syntax_tests/data/parsing/grammar/expressions/expected/locallyAbstractTypes.res.txt

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
let f (type t) [arity:1](xs : t list) = ()
2-
let f (type t) [arity:2](xs : t list) (type s) (ys : s list) = ()
2+
let f (type t) (type s) [arity:2](xs : t list) (ys : s list) = ()
33
let f (type t) (type u) (type v) [arity:1](xs : (t * u * v) list) = ()
4-
let f (type t) (type u) (type v) [arity:2](xs : (t * u * v) list) (type s)
5-
(type w) (type z) (ys : (s * w * z) list) = ()
6-
let f = ((fun (type t) -> fun (type u) -> fun (type v) ->
7-
fun [arity:2](xs : (t * u * v) list) -> ((fun (type s) -> fun (type w) ->
8-
fun (type z) -> fun (ys : (s * w * z) list) -> ())[@attr2 ]))
9-
[@attr ])
10-
let f = ((fun (type t) -> ((fun (type s) ->
11-
fun [arity:2](xs : (t * s) list) -> ((fun (type u) -> ((fun (type v) -> fun
12-
(type w) -> fun (ys : (u * v * w) list) -> ())[@attr ]))[@attr ]))
13-
[@attr ]))[@attr ])
4+
let f (type t) (type u) (type v) (type s) (type w) (type z)
5+
[arity:2](xs : (t * u * v) list) (ys : (s * w * z) list) = ()
6+
let f = ((fun (type t) -> fun (type u) -> fun (type v) -> fun (type s) -> fun
7+
(type w) -> fun (type z) ->
8+
fun [arity:2](xs : (t * u * v) list) -> fun (ys : (s * w * z) list) -> ())
9+
[@attr ][@attr2 ])
10+
let f = ((fun (type t) -> fun (type s) -> fun (type u) -> fun (type v) -> fun
11+
(type w) ->
12+
fun [arity:2](xs : (t * s) list) -> fun (ys : (u * v * w) list) -> ())
13+
[@attr ][@attr ][@attr ][@attr ])
1414
let cancel_and_collect_callbacks :
1515
'a 'u 'c .
1616
packed_callbacks list ->

0 commit comments

Comments
 (0)