Closure parameter wrapping appears to ignore block-prefix width
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 1.1k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 24
Description
Translation assisted by an LLM.
Summary
The decision to wrap closure parameters appears not to account for the full
width between the closing | and the opening { of the body. Prefixes such as
unsafe, async, and async move can make the line exceed max_width, but
rustfmt still joins the parameters onto that line.
Is this a width-budget bug, or an intentional formatting rule?
I tried to format this standalone example, which compiles with Rust edition 2024
(with warnings):
fn accept<F>(_: F) {}
fn main() {
accept(
move |first_argument_name_long: u64,
second_argument_name_long: u64| unsafe {
let value = 1;
value
},
);
}
Expected behavior
Keep the resulting code within max_width = 80, for example by splitting the
closure parameters or using another suitable layout for the closure body.
I am not requesting preservation of arbitrary manual line breaks.
Actual behavior
Rustfmt produces:
fn accept<F>(_: F) {}
fn main() {
accept(
move |first_argument_name_long: u64, second_argument_name_long: u64| unsafe {
let value = 1;
value
},
);
}
The closure's first line is 85 columns including indentation, exceeding the
configured 80-column limit. Formatting exits successfully without warnings.
Splitting the parameters manually results in the same 85-column line again.
Configuration
rustfmt.toml:
max_width = 80
use_small_heuristics = "Max"
style_edition = "2027"
Command:
rustfmt +nightly --edition 2024 --config-path rustfmt.toml < repro.rs
The language edition is 2024; the formatting style edition is 2027.
Reproduction Steps
- Save the input above as
repro.rsin a temporary directory. - Save the configuration above as
rustfmt.tomlin the same directory. - Run the command above from that directory.
- Observe that the two parameter lines are joined into an 85-column line.
Meta
Tested nightly version:
rustfmt 1.10.0-nightly (67854e511d 2026-08-15)
This is the installed nightly tested, not a claim about the latest nightly.
The same example also reproduces on the following stable version with
style_edition = "2024" and otherwise the same configuration:
rustfmt 1.9.0-stable (59807616e1 2026-04-14)
Additional observations
In the same example, changing only the body prefix produces 78 columns for
{, 84 for async {, 89 for async move {, and 85 for unsafe {. All four
keep the parameters on one line. This is not specific to async blocks.
Related issues
Possibly related: #325 (closed), #2063, #6831, #6538 and #6687. Here rustfmt actively joins
breakable parameters into an over-width line, rather than preserving unformatted
input. Please let me know if an existing issue already covers this case.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by saving the supplied example as repro.rs with the shown rustfmt.toml, then run the documented rustfmt +nightly command to reproduce the over-width output. Trace the closure-parameter formatting entry point and add or update a regression test for the prefixes shown; done means formatting respects max_width = 80 without warnings.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100