rust-lang / rustfmt

Format Rust code
https://rust-lang.github.io/rustfmt/
Apache License 2.0
6.04k stars 888 forks source link

Trailing whitespace followed by long unbreakable line causes error[internal]: left behind trailing whitespace #5711

Open mk12 opened 1 year ago

mk12 commented 1 year ago

Input code

fn f() {
    match x {
        0 => S {

        },
        _ => AAAAAAAAA,
    }
}

(Note, the 4th line contains 12 spaces, which you can see if you select the text.)

Actual result

$ rustfmt file.rs --config max_width=20
error[internal]: left behind trailing whitespace
 --> /usr/local/google/home/mkember/a.rs:4:4:1
  |
4 |
  | ^^^^^^^^^^^^
  |

warning: rustfmt has failed to format. See previous 1 errors. 
$ echo $?
1

Expected result

Here are some possibilities, from best to worst (IMO):

  1. Successfully delete the trailing whitespace. I'm not sure why the long line that follows prevents it from doing so.
  2. Print a warning that it wasn't able to remove trailing whitespace, but still succeed (exit status 0).
  3. Provide an option that makes such errors non-fatal (I though error_on_unformatted=false would, but it does not).

If you're running rustfmt manually on your own code this isn't such a big deal. But in my case I am running it automatically on Rust bindings code generated by a program. I want to fail the whole program is rustfmt fails on a real problem, like invalid Rust syntax. I don't want it to fail just because it wasn't able to format optimally. One solution (at least for this example) is to make max_width very large, but that makes everything else less readable. The whole point of running rustfmt is so I can generate ugly code without worrying about formatting.

ytmimi commented 1 year ago

rustfmt typically doesn't play nicely with generated code. There are other closed issues, but you can check out #5422 as an example.

I'm not sure why the long line that follows prevents it from doing so.

rustfmt is bound by the max_width constraint, and I believe that if rustfmt fails to format any match arm it gives up on formatting the entire match expression (possibly related to #4797). Without looking at the exact snippet that's causing your error[internal]: left behind trailing whitespace the best advice I can give is to bump the max width.

  1. Provide an option that makes such errors non-fatal (I though error_on_unformatted=false would, but it does not).

Leaning towards this as a solution to allow users to ignore left behind trailing whitespace warnings.

mk12 commented 1 year ago

I see, thanks for explaining. I didn't realize max_width was such a hard constraint rather than just a goal. I guess my best option is to use a very large max_width and emit newlines liberally, i.e. trust rustfmt to handle ugly vertical code rather than ugly horizontal code. If I could instead use (3) at some point that would be great (I suppose I could parse error messages myself, but that would be brittle).

calebcartwright commented 1 year ago

Provide an option that makes such errors non-fatal (I though error_on_unformatted=false would, but it does not).

FWIW we're planning on doing this for both error_on_line_overflow (https://github.com/rust-lang/rustfmt/issues/3391) and error_on_unformatted, just that like many of the dev tools teams we've extremely limited bandwidth and doing so isn't a top priority

fightling commented 1 year ago

Thank you for your explanation. I just got stuck at the same point.

Sadly Visual Code does not mention any error and my code (which usually gets formatted automatically) just remained unformatted and I was wondering.

novedevo commented 1 year ago

thank you for all your work on rustfmt! I hit this organically (i.e. non-generated code), glad to see it's already a known issue. I hope you get more development resources to keep making excellent dev tools :)

FrankTaylorLieder commented 5 months ago

I've just hit this issue, with a single trailing space in a match arm... reporting details in case this version of the problem has not been seen. Here is the affected code:

fn determine_instructions(ng: &Option<NextGap>) -> String {
    let message = match ng {
        None => "No gaps to fill, done! Press 'S' to save.".to_string(),
        Some(ng) => 
            format!("Next gap: {}, after {}. Click to place a point, BS to remove a point, 'N' to finish the section, 'S' to save.", ng.gap, ng.previous)
    };
    ...

There is a trailing space after the Some match branch.

I get this error:

fst:tfl-tracker/ (20240603-mapper✗) $ cargo fmt                                                                                            [10:36:21]
error[internal]: left behind trailing whitespace
  --> /Volumes/Motif Data/fst/Documents/personal/src/tfl/tfl-tracker/src/mapper_ui.rs:55:55:20
   |
55 |         Some(ng) =>
   |                    ^
   |

warning: rustfmt has failed to format. See previous 1 errors.

I just noticed that this file stopped formatting automatically on save (neovim), but the editor did not surface the rustfmt error.

As suggested above, I think making this a soft error and continuing with the rest of the file is a good option.

Many thanks... I love that there is just one formatting standard for Rust!