Skip to content

Commit 3ca9d2e

Browse files
committed
Fix unstable formatting of trailing callback comments
Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent cf94640 commit 3ca9d2e

5 files changed

Lines changed: 114 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535

3636
#### :bug: Bug fix
3737

38+
- Fix unstable formatting of trailing comments in nested callbacks. https://github.com/rescript-lang/rescript/issues/6976
39+
3840
- Fix excessive parentheses and indentation in function assignments to refs, align record and array assignment formatting across refs and fields, and preserve function return-type parentheses and consistent JSX fragment layout in callbacks. https://github.com/rescript-lang/rescript/pull/8611
3941
- Fix a recursive module with an empty signature discarding its right-hand side. Lambda-to-Lam conversion rewrote `Pupdate_mod` to unit when the module's shape had no fields, dropping the primitive's arguments - one of which is the right-hand side - so `module rec M: {} = { let () = Console.log("effect") }` emitted nothing for `M`. The elision now happens where the bindings are produced, with the right-hand side still in hand. https://github.com/rescript-lang/rescript/pull/8608
4042
- Fix `Int.Ref.increment` and `Int.Ref.decrement` evaluating their argument twice: `Int.Ref.increment(mkRef())` emitted `mkRef().contents = mkRef().contents + 1 | 0`. The `%incr` and `%decr` builtins lowered to an assignment that repeated the argument expression; they now bind the reference before the read-modify-write. Inlining decisions around an increment are taken on the code it stands for rather than on a single primitive node. https://github.com/rescript-lang/rescript/pull/8608

compiler/syntax/src/res_printer.ml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4657,14 +4657,28 @@ and print_pexp_apply ~state expr cmt_tbl =
46574657
| Braced braces -> print_braces doc call_expr braces
46584658
| Nothing -> doc
46594659
in
4660-
if Parsetree_viewer.requires_special_callback_printing_first_arg args then
4660+
(* Use the regular argument layout for trailing comments. Compact callback
4661+
* layouts can detach comments from the body when it breaks, making
4662+
* subsequent formatting unstable. *)
4663+
let args_have_trailing_comments =
4664+
List.exists
4665+
(fun (_, (arg : Parsetree.expression)) ->
4666+
has_trailing_comments cmt_tbl arg.pexp_loc)
4667+
args
4668+
in
4669+
if
4670+
(not args_have_trailing_comments)
4671+
&& Parsetree_viewer.requires_special_callback_printing_first_arg args
4672+
then
46614673
let args_doc =
46624674
print_arguments_with_callback_in_first_position ~state ~partial args
46634675
cmt_tbl
46644676
in
46654677
Doc.concat
46664678
[print_attributes ~state attrs cmt_tbl; call_expr_doc; args_doc]
4667-
else if Parsetree_viewer.requires_special_callback_printing_last_arg args
4679+
else if
4680+
(not args_have_trailing_comments)
4681+
&& Parsetree_viewer.requires_special_callback_printing_last_arg args
46684682
then
46694683
let args_doc =
46704684
print_arguments_with_callback_in_last_position ~state ~partial args
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
let rec fib = (n, k) =>
2+
switch n {
3+
| 0 | 1 => k(1)
4+
| _ =>
5+
Suspend(
6+
() =>
7+
fib(n - 1, (v0) =>
8+
fib(n - 2, (v1) =>
9+
k(v0 + v1)
10+
/* comment */
11+
)
12+
),
13+
)
14+
}
15+
16+
let first = call(x => x
17+
/* first callback */
18+
, value)
19+
20+
let last = call(value, x => x
21+
// last callback
22+
)
23+
24+
let inline = call(value, x => x // inline callback
25+
)
26+
27+
let firstInline = call(x => x // first inline callback
28+
, value)
29+
30+
let nested = call(value, x => call(value, y => y
31+
/* nested callback */
32+
))
33+
34+
let blocks = call(value, x => x /* inline block */)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
let rec fib = (n, k) =>
2+
switch n {
3+
| 0 | 1 => k(1)
4+
| _ =>
5+
Suspend(
6+
() =>
7+
fib(n - 1, v0 =>
8+
fib(
9+
n - 2,
10+
v1 => k(v0 + v1),
11+
/* comment */
12+
)
13+
),
14+
)
15+
}
16+
17+
let first = call(
18+
x => x,
19+
/* first callback */
20+
value,
21+
)
22+
23+
let last = call(
24+
value,
25+
x => x,
26+
// last callback
27+
)
28+
29+
let inline = call(value, x => x) // inline callback
30+
31+
let firstInline = call(x => x, value) // first inline callback
32+
33+
let nested = call(value, x =>
34+
call(
35+
value,
36+
y => y,
37+
/* nested callback */
38+
)
39+
)
40+
41+
let blocks = call(value, x => x /* inline block */)

tests/syntax_tests/res_test.ml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,27 @@ let x: int
2828

2929
let () = print_endline "✅ multi printer api tests"
3030

31+
let () =
32+
let filename =
33+
Filename.concat data_dir "printer/comments/callbackTrailing.res"
34+
in
35+
let source = IO.read_file ~filename in
36+
let format ~width source =
37+
let result =
38+
Res_driver.parse_implementation_from_source ~for_printer:true
39+
~display_filename:filename ~source
40+
in
41+
assert (not result.invalid);
42+
Res_printer.print_implementation ~width result.parsetree
43+
~comments:result.comments
44+
in
45+
List.iter
46+
(fun width ->
47+
let printed = format ~width source in
48+
assert (printed = format ~width printed))
49+
[20; 40; 80; 100; 120];
50+
print_endline "✅ callback trailing comments are stable at multiple widths"
51+
3152
module Outcome_printer_tests = struct
3253
let signature_to_outcome structure =
3354
Lazy.force Res_outcome_printer.setup;

0 commit comments

Comments
 (0)