Repository navigation
Keep a line comment in a block construct's operand in the operand - #9061
Conversation
Why:
A trailing line comment is printed at the next line break of a breaking
group. In a flat operand such as `obj.x`, `obj["m"]` or `obj->f`, that
is the break after the block's `{`, so formatting moved the comment
after the `{` and on the next run into the block. When the comment is
still pending at the end of the operand of `switch`, `if`, `while`,
`for`, `for..of`, `for await..of` or `try`, the operand now goes into
parentheses with the comment before the `)`.
Format modified (switch operand):
Example:
switch obj // c
.x {
| _ => ()
}
Before (rescript): first run, then second run
switch obj.x { // c
| _ => ()
}
⇝
switch obj.x {
// c
| _ => ()
}
After (rescript): stable
switch (
obj.x // c
) {
| _ => ()
}
Review: Does code that formatted stably before change? No: an operand only
gets parentheses when a line comment in it is still queued at its end,
which always moved the comment. No existing snapshot changes.
Fixes: #9060
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo
Signed-off-by: Christoph Knittel <ck@cca.io>
Changelog🐛 Bug fix
Semantic Diff4 commits · Full page Keep a line comment in a block construct's operand in the operande5db72d · cknitt + Claude · Oct 27, 2026, 07:03 UTC
Format modified (switch operand) switch obj // c
.x {
| _ => ()
}
-switch obj.x { // c
-| _ => ()
-}
-⇝
-switch obj.x {
-// c
+switch (
+ obj.x // c
+) {
| _ => ()
}Review
Keep a line comment in an operand that has its own parentheses8bf8c32 · cknitt + Claude · Oct 27, 2026, 08:14 UTC
Such an operand now breaks its own parentheses when a comment is pending, which keeps the comment before the Format modified (parenthesized switch operand) switch (f(
a, // c
b,
) :> int) {
| _ => ()
}
switch (
- (f(a, b) :> int) // c
+ f(a, b) :> int // c
) {
| _ => ()
}
-⇝
-switch (f(a, b) :> int) {
-// c
-
-| _ => ()
-}✨ Print the operands of switch, try and loops with one helper631dbaf · cknitt + Claude · Oct 27, 2026, 10:35 UTC · new The operands of switch, try, for, for..of and for await..of were each printed by the same block: the expression, its parentheses or braces, and print_operand_before_brace. print_block_operand does that once; if and while keep their own condition printing. The output is unchanged. ✨ Test line comments after the items of a block construct's operand364e152 · cknitt + Claude · Oct 27, 2026, 10:36 UTC · new These cases from the dropped #8906 guard the parentheses against a comment after an item of an array, list, tuple, record or call, after a pipe's receiver, and before the operator of a binary expression or pipe inside an item, under switch, if, while, for..of and try. Each formats the same again. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #9061 +/- ##
==========================================
+ Coverage 81.42% 81.44% +0.01%
==========================================
Files 459 459
Lines 64547 64553 +6
==========================================
+ Hits 52559 52573 +14
+ Misses 11988 11980 -8
🚀 New features to boost your workflow:
|
rescript
@rescript/belt
@rescript/darwin-arm64
@rescript/linux-arm64
@rescript/linux-x64
@rescript/runtime
@rescript/win32-x64
commit: |
|
Developer playground preview: https://rescript-lang.github.io/rescript/dev-playground/?version=pr-9061 |
Why:
#9061 keeps a line comment in the operand of switch, try, if, while or a
loop by putting the operand into parentheses when
Doc.has_pending_line_suffix finds the comment still queued at its end.
A comment after an item or argument then moves to the end of the
operand, away from the item it describes.
The operand now first breaks the groups around such a comment
(Doc.break_before_line_suffixes), so the comment stays after its item and
the parentheses are only needed when it is still pending. A binary
expression is left flat: breaking it would flush the comment after the
operator, where the next format attaches it to the right operand, so it
keeps #9061's parentheses.
Format modified (line comment in a switch operand):
Example:
let x = switch [
a, // c
b,
] {
| _ => 1
}
Before (rescript):
let x = switch (
[a, b] // c
) {
| _ => 1
}
After (rescript):
let x = switch [
a, // c
b,
] {
| _ => 1
}
Review: Why not make every same-line line comment break its group? That changes code that formats stably today, such as foo(v :> b) // comment, which would split over three lines; the drift only happens before a block.
Review: Why are binary operands exempt? With their group broken, `switch a // c\n+ b {` printed `a + // c\nb` and then `a +\n// c\nb` on the next format; flat, it prints `switch (\n a + b // c\n) {` and stays.
Area: printer tests
Output: unchanged
Formatting: operands of switch, try, if, while and loops with a line comment
after an item or argument keep it there; binary operands keep #9061's
parentheses
Formats: none
PPX: unchanged
Editor: unchanged
Tests: +tests/syntax_tests/data/printer/comments/operandBeforeBlock.res
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUpL6dKCiSwAeriDGRHqNr
Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo
Signed-off-by: Christoph Knittel <ck@cca.io>
Why:
A coercion or type constraint operand is printed in its own parentheses.
A comment still pending at its end got a second pair around them and
was printed after the inner `)`. That position is not adjacent to the
operand, so the next format attached the comment to the first case and
moved it into the block (#9060).
Such an operand now breaks its own parentheses when a comment is pending,
which keeps the comment before the `)`. A `while` condition with its own
parentheses no longer gets the extra pair it adds when a condition breaks.
Format modified (parenthesized switch operand):
Example:
switch (f(
a, // c
b,
) :> int) {
| _ => ()
}
Before (rescript): first run, then second run
switch (
(f(a, b) :> int) // c
) {
| _ => ()
}
⇝
switch (f(a, b) :> int) {
// c
| _ => ()
}
After (rescript): stable
switch (
f(a, b) :> int // c
) {
| _ => ()
}
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo
Signed-off-by: Christoph Knittel <ck@cca.io>
Why:
#9061 keeps a line comment in the operand of switch, try, if, while or a
loop by putting the operand into parentheses when
Doc.has_pending_line_suffix finds the comment still queued at its end.
A comment after an item or argument then moves to the end of the
operand, away from the item it describes.
The operand now first breaks the groups around such a comment
(Doc.break_before_line_suffixes), so the comment stays after its item and
the parentheses are only needed when it is still pending. A binary
expression is left flat: breaking it would flush the comment after the
operator, where the next format attaches it to the right operand, so it
keeps #9061's parentheses. In an operand with its own parentheses, such as
a coercion, the comment also stays after its item inside them
(operandLineComment.res).
Format modified (line comment in a switch operand):
Example:
let x = switch [
a, // c
b,
] {
| _ => 1
}
Before (rescript):
let x = switch (
[a, b] // c
) {
| _ => 1
}
After (rescript):
let x = switch [
a, // c
b,
] {
| _ => 1
}
Review: Why not make every same-line line comment break its group? That changes code that formats stably today, such as foo(v :> b) // comment, which would split over three lines; the drift only happens before a block.
Review: Why are binary operands exempt? With their group broken, `switch a // c\n+ b {` printed `a + // c\nb` and then `a +\n// c\nb` on the next format; flat, it prints `switch (\n a + b // c\n) {` and stays.
Area: printer tests
Output: unchanged
Formatting: operands of switch, try, if, while and loops with a line comment
after an item or argument keep it there; binary operands keep #9061's
parentheses
Formats: none
PPX: unchanged
Editor: unchanged
Tests: +tests/syntax_tests/data/printer/comments/operandBeforeBlock.res
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUpL6dKCiSwAeriDGRHqNr
Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo
Signed-off-by: Christoph Knittel <ck@cca.io>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Why:
Only a binary operand was left flat. A binary expression inside another
operand, as in `[a // c\n+ b]`, still had its group broken, so the
comment was printed after the operator and the next format attached it
to the right operand.
An operand is now also left flat when a binary expression or pipe in it has
its operator at the start of a line, after the left operand, which is where
such a comment sits (Parsetree_viewer.has_line_break_before_operator). The
comment then goes into #9061's parentheses. A comment after an item that
holds a binary expression keeps its place.
Format modified (binary expression in an array operand):
Example:
let x = switch [a // c
+ b, d] { | _ => 1 }
Before (rescript): first run, then second run
let x = switch [
a + // c
b,
d,
] {
| _ => 1
}
⇝
let x = switch [
a +
// c
b,
d,
] {
| _ => 1
}
After (rescript): stable
let x = switch (
[a + b, d] // c
) {
| _ => 1
}
Review: Why look at the line of the operator rather than at the comments? A line comment between the left operand and the operator always puts the operator on a later line, and the check needs only the expression, before printing takes the comments out of the table. A multi-line binary expression without such a comment only costs another comment in the same operand its place next to its item.
Area: printer tests
Output: unchanged
Tests: ~tests/syntax_tests/data/printer/comments/operandBeforeBlock.res
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo
Signed-off-by: Christoph Knittel <ck@cca.io>
The operands of switch, try, for, for..of and for await..of were each printed by the same block: the expression, its parentheses or braces, and print_operand_before_brace. print_block_operand does that once; if and while keep their own condition printing. The output is unchanged. Area: printer Output: unchanged Formatting: unchanged, no snapshot changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo Signed-off-by: Christoph Knittel <ck@cca.io>
These cases from the dropped #8906 guard the parentheses against a comment after an item of an array, list, tuple, record or call, after a pipe's receiver, and before the operator of a binary expression or pipe inside an item, under switch, if, while, for..of and try. Each formats the same again. Area: tests Output: unchanged Tests: ~tests/syntax_tests/data/printer/comments/operandLineComment.res Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo Signed-off-by: Christoph Knittel <ck@cca.io>
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
A trailing line comment in the operand of
switch,if,while,for,for..of,for await..ofortrywas printed after the block's{and, on the next run, moved into the block. Now, when such a comment is still pending at the end of the operand (Doc.has_pending_line_suffix), the operand goes into parentheses with the comment before the):switch (\n obj.x // c\n) {.Only operands whose comment would have moved get the parentheses, so no existing snapshot changes.
Fixes #9060.
New printer fixture
comments/operandLineComment.rescovers every reproduction from the issue.Interaction with #8906: it adds
print_operand_before_braceat the same call sites, breaking groups before a line comment and adding parentheses for comments outside any group. Combined, itshas_ungrouped_line_suffixwould be replaced by thishas_pending_line_suffix.🤖 Generated with Claude Code
https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo