Skip to content

[Tracking] Formatting failures with all-or-nothing fallback behavior #6687

@shulaoda

Description

@shulaoda

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

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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions