-
Notifications
You must be signed in to change notification settings - Fork 957
Description
Summary
When rustfmt encounters an unformattable element in a statement (e.g., long strings exceeding max_width
, insufficient macro formatting support, problematic block comments), it abandons formatting the entire statement instead of attempting partial formatting. This all-or-nothing fallback behavior results in:
- Unformatted statements (original source preserved verbatim)
- Trailing whitespace errors (
error[internal]: left behind trailing whitespace
)
Root Cause
Rustfmt expects to successfully rewrite every element in a statement. When any single element cannot be formatted, the entire statement formatting is aborted and the original source is preserved verbatim. This affects various constructs including method chains (in src/chains.rs
), match expressions, and other complex statements.
The problem is that rustfmt currently has no graceful degradation strategy when it cannot format part of a statement. The team is actively working on improving this behavior.
Examples
1. Method chains with long string arguments (#3863)
// Input: Chain with one long string argument
foo("short").long("very long text that exceeds max width").baz().collect();
// Expected: Wrapped across lines (with format_strings=true)
foo("short")
.long(
"very long text that exceeds max \
width",
)
.baz()
.collect();
// Actual: Preserved as-is, entire chain unformatted
// Workaround: Set format_strings=true
2. Macro chains with trailing whitespace (#6649)
// Input: Macro chain with internal formatting issues
bolero::check!()
.with_type::<FlowKey>()
.for_each(|x| {
let a = 1;
⎵⎵⎵⎵ // ← trailing whitespace preserved
let very_long_line = "exceeds max_width...";
});
// Issue: Long string causes chain formatting to fail → fallback preserves trailing whitespace → error[internal]
// Workaround: Manually remove trailing whitespace before running rustfmt or set format_strings=true
3. Macros with unusual formatting (#6659)
// Input: Closure with macro containing excessive whitespace
true.then(|| {⎵⎵ // ← trailing whitespace preserved
println! { "{}",
0
};
});
// Issue: Insufficient macro formatting support causes entire statement to fall back → trailing whitespace preserved → error[internal]
// Workaround: Manually reformat the macro or remove trailing whitespace
4. Match expressions with block comments (#6663)
// Input: Match expression with block comment after scrutinee
fn main() {
match () /*x*/ {
// ^^^^^ Culprit. Remove the x, or replace the whole blockcomment with spaces and it'll format
⎵⎵⎵⎵ // ← trailing whitespace preserved
_ => {}
}
}
// Issue: Block comment causes match expression formatting to fail → fallback preserves trailing whitespace → error[internal]
// Workaround: Remove the block comment or manually remove trailing whitespace
Related Issues
- Gives up on chains if any line is too long. #3863
- error[internal]: left behind trailing whitespace (full repro with GitHub link to offending repo) #6649
- "error[internal]: left behind trailing whitespace" with long macro inside closure #6659
- Error formatting with block comment after match scrutinee #6663
- rustfmt does not format this code #6634
Workarounds
Most cases are caused by long string arguments. Setting format_strings = true
in rustfmt.toml
(requires nightly version) allows rustfmt to format long strings, preventing the chain formatting fallback. Alternatively, manually remove trailing whitespace before running rustfmt.
Note that some of these issues can be directly resolved by fixing specific formatting bugs (e.g., block comment handling), while others may require significant long-term improvements to the formatting infrastructure (e.g., graceful degradation for long strings).
References
Please feel free to modify the description to make it easier to understand or more accurate. If it's not necessary, please feel free to close it.