Skip to content

pmt fmt: a line comment between stacked labels and the command needs two passes to settle #96

Description

@mellonis

pmt fmt needs two passes to settle on one input shape: a line comment written between a statement's stacked labels and its command. The second pass is stable, so the output is correct — but pmt fmt --check reports a change on a file that has already been formatted, and format-on-save leaves the buffer dirty for one extra round.

Reproduction

main() {
 1:
 // mid
 2: left;
}
pass 1: "main() {\n  1: 2: // mid\n        left;\n}\n"
pass 2: "main() {\n 1: 2:\n    // mid\n    left;\n}\n"
pass 3: identical to pass 2

Pass 1 restacks the labels and pulls the comment up as a trailing comment on the label line, which pushes the command to column 8. Pass 2 sees the restacked labels, decides the comment is an own-line one after all, and settles.

Scope — narrower than it looks

Only the // form, and only between stacked labels and the command. These three neighbours are all idempotent on the first pass:

main() {\n 1:\n /* mid */\n 2: left;\n}\n     block comment      -> stable
main() {\n 1:\n // mid\n left;\n}\n          single label       -> stable
main() {\n // mid\n 1: left;\n}\n            comment above      -> stable

Not a regression

This is inherited, not introduced by the green-tree formatter. The pre-green printer produces byte-identical pass-1 and pass-2 output on the same input, verified against a build of it. The behavior is pinned by a two-pass fixture so it cannot drift silently, and the idempotence claim in the repo's own notes carries the exception.

Why it is worth fixing anyway

fmt --check is meant to answer "is this file formatted?" and on this shape it answers no about a file that is. Anything wiring --check into CI or a pre-commit hook sees a failure with no user-applicable fix other than running fmt twice.

Where to look

The interaction is between label restacking and trailing-comment attribution: on pass 1 the labels are still on separate lines when the comment's role is decided, so it qualifies as same-line trailing; after restacking it no longer does. A fix likely means deciding the comment's role against the layout the printer is about to produce rather than the one it read — or accepting the pass-1 shape as canonical and making pass 2 agree with it instead.

Whichever direction, the property suite in crates/post-machine/tests/fmt_property.rs currently EXCLUDES this shape from generation with the reason recorded; that exclusion comes out as part of the fix, and its removal is the test that the fix worked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions