Skip to content

Commit 8179a59

Browse files
committed
Share argument locations and clarify callback layout rules
Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent a553707 commit 8179a59

5 files changed

Lines changed: 62 additions & 62 deletions

File tree

compiler/syntax/src/res_comments_table.ml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -986,13 +986,8 @@ and walk_expression expr t comments =
986986
attach t.trailing call_expr.Parsetree.pexp_loc after_expr;
987987
walk_list
988988
(arguments
989-
|> List.map (fun (lbl, expr) ->
990-
let loc =
991-
match lbl with
992-
| Asttypes.Labelled {loc} | Optional {loc} ->
993-
{loc with loc_end = expr.Parsetree.pexp_loc.loc_end}
994-
| _ -> expr.pexp_loc
995-
in
989+
|> List.map (fun ((_, expr) as argument) ->
990+
let loc = Parsetree_viewer.argument_loc argument in
996991
ExprArgument {expr; loc}))
997992
t rest
998993
in

compiler/syntax/src/res_parsetree_viewer.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
open Parsetree
22

3+
let argument_loc (lbl, (arg : Parsetree.expression)) =
4+
match lbl with
5+
| Asttypes.Labelled {loc} | Optional {loc} ->
6+
{loc with loc_end = arg.pexp_loc.loc_end}
7+
| Nolabel -> arg.pexp_loc
8+
39
let arrow_type ct =
410
match ct with
511
| {ptyp_desc = Ptyp_arrow {params; ret}; ptyp_attributes = attrs} ->

compiler/syntax/src/res_parsetree_viewer.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
(* Full argument span used for comment attachment and printing. For labeled
2+
* and optional arguments it starts at the label and ends at the expression. *)
3+
val argument_loc : Asttypes.arg_label * Parsetree.expression -> Location.t
4+
15
(* Restructures a nested tree of arrow types into its args & returnType
26
* The parsetree contains: a => b => c => d, for printing purposes
37
* we restructure the tree into (a, b, c) and its returnType d *)

compiler/syntax/src/res_printer.ml

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,29 @@ let has_trailing_comments tbl loc =
9393
| None -> false
9494
| _ -> true
9595

96-
(* Match the full argument location used by comment attachment. *)
97-
let argument_loc (lbl, (arg : Parsetree.expression)) =
98-
match lbl with
99-
| Asttypes.Labelled {loc} | Optional {loc} ->
100-
{loc with loc_end = arg.pexp_loc.loc_end}
101-
| Nolabel -> arg.pexp_loc
102-
10396
let has_leading_comments tbl loc =
10497
match Hashtbl.find_opt tbl.Comment_table.leading loc with
10598
| None -> false
10699
| _ -> true
107100

101+
(* Compact layouts print expression comments but not comments on the full
102+
* labeled argument. For unlabeled arguments, leading expression comments
103+
* already work in the compact layout; forcing a different layout can make
104+
* comments exposed by removing parameter parentheses unstable. *)
105+
let argument_requires_regular_layout cmt_tbl ((lbl, arg) as argument) =
106+
let loc = Parsetree_viewer.argument_loc argument in
107+
let has_leading_label_comments =
108+
match lbl with
109+
| Asttypes.Nolabel -> false
110+
| Labelled _ | Optional _ ->
111+
has_leading_comments cmt_tbl loc
112+
|| has_leading_comments cmt_tbl arg.Parsetree.pexp_loc
113+
in
114+
(* Trailing comments can escape compact layouts when the body breaks. *)
115+
has_leading_label_comments
116+
|| has_trailing_comments cmt_tbl loc
117+
|| has_trailing_comments cmt_tbl arg.pexp_loc
118+
108119
let print_multiline_comment_content txt =
109120
(* Turns
110121
* |* first line
@@ -4533,35 +4544,19 @@ and print_pexp_apply ~state expr cmt_tbl =
45334544
| Braced braces -> print_braces doc call_expr braces
45344545
| Nothing -> doc
45354546
in
4536-
(* Use the regular layout for comments attached to arguments. Compact
4537-
* callback layouts can detach trailing comments when the body breaks and
4538-
* skip leading comments attached to the full labeled argument. *)
4539-
let args_have_comments =
4540-
List.exists
4541-
(fun (lbl, (arg : Parsetree.expression)) ->
4542-
let loc = argument_loc (lbl, arg) in
4543-
let has_leading_label_comments =
4544-
match lbl with
4545-
| Asttypes.Nolabel -> false
4546-
| Labelled _ | Optional _ ->
4547-
has_leading_comments cmt_tbl loc
4548-
|| has_leading_comments cmt_tbl arg.pexp_loc
4549-
in
4550-
has_leading_label_comments
4551-
|| has_trailing_comments cmt_tbl loc
4552-
|| has_trailing_comments cmt_tbl arg.pexp_loc)
4553-
args
4547+
let requires_regular_layout =
4548+
List.exists (argument_requires_regular_layout cmt_tbl) args
45544549
in
45554550
let args_doc, maybe_break_parent =
45564551
if
4557-
(not args_have_comments)
4552+
(not requires_regular_layout)
45584553
&& Parsetree_viewer.requires_special_callback_printing_first_arg args
45594554
then
45604555
( print_arguments_with_callback_in_first_position ~state ~partial args
45614556
cmt_tbl,
45624557
Doc.nil )
45634558
else if
4564-
(not args_have_comments)
4559+
(not requires_regular_layout)
45654560
&& Parsetree_viewer.requires_special_callback_printing_last_arg args
45664561
then
45674562
let args_doc =
@@ -5137,7 +5132,8 @@ and print_arguments ~state ~partial
51375132
List.exists
51385133
(fun ((_, arg) as argument) ->
51395134
Parsetree_viewer.is_fun_expr arg
5140-
&& (has_any_trailing_line_comment cmt_tbl (argument_loc argument)
5135+
&& (has_any_trailing_line_comment cmt_tbl
5136+
(Parsetree_viewer.argument_loc argument)
51415137
|| has_any_trailing_line_comment cmt_tbl arg.pexp_loc))
51425138
args
51435139
in

tests/syntax_tests/res_test.ml

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,39 +33,38 @@ let () =
3333
Filename.concat data_dir "printer/comments/callbackTrailing.res"
3434
in
3535
let source = IO.read_file ~filename in
36-
let format ~width source =
36+
let parse source =
3737
let result =
38-
Res_driver.parse_implementation_from_source ~for_printer:true
39-
~display_filename:filename ~source
38+
Res_driver.parse_implementation_from_source ~display_filename:filename
39+
~source
4040
in
4141
assert (not result.invalid);
42-
let printed =
43-
Res_printer.print_implementation ~width result.parsetree
44-
~comments:result.comments
45-
in
46-
let reparsed =
47-
Res_driver.parse_implementation_from_source ~for_printer:true
48-
~display_filename:filename ~source:printed
49-
in
50-
assert (not reparsed.invalid);
51-
let comment_texts comments =
52-
List.map (fun comment -> String.trim (Res_comment.txt comment)) comments
53-
in
54-
if comment_texts result.comments <> comment_texts reparsed.comments then
55-
failwith
56-
(Printf.sprintf
57-
"Callback formatting changed comments at width %d.\n\
58-
Source:\n\
59-
%s\n\
60-
Printed:\n\
61-
%s"
62-
width source printed);
63-
printed
42+
result
43+
in
44+
let format ~width result =
45+
Res_printer.print_implementation ~width result.Res_driver.parsetree
46+
~comments:result.comments
47+
in
48+
let comment_texts result =
49+
List.map
50+
(fun comment -> String.trim (Res_comment.txt comment))
51+
result.Res_driver.comments
6452
in
6553
List.iter
6654
(fun width ->
67-
let printed = format ~width source in
68-
let reprinted = format ~width printed in
55+
let original = parse source in
56+
let printed = format ~width original in
57+
let reparsed = parse printed in
58+
if comment_texts original <> comment_texts reparsed then
59+
failwith
60+
(Printf.sprintf
61+
"Callback formatting changed comments at width %d.\n\
62+
Source:\n\
63+
%s\n\
64+
Printed:\n\
65+
%s"
66+
width source printed);
67+
let reprinted = format ~width reparsed in
6968
if printed <> reprinted then
7069
failwith
7170
(Printf.sprintf

0 commit comments

Comments
 (0)