rust-lang / rustfmt

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

Formatting error ('left behind trailing whitespace') on if statement with comment between `&&` and expression #6342

Closed antonilol closed 2 months ago

antonilol commented 2 months ago

Reproducer:

fn fn1() {
    #[derive(PartialEq)]
    struct Struct {
        looooooooooooooong_field_name: u8,
    }

    if None
                                    == Some(Struct {
                                        looooooooooooooong_field_name: 1, 
                                    })
                                    &&
                                    // removing this comment makes it format as usual
                                     true
    {
        todo!();
    }
}

(This is a minimal example of the format error made from real code, this is why there is a nonsensical None == Some(...) comparison, && true and a todo!())

Trying to use rustfmt (through cargo fmt) on this results in an error and the code being partially formatted.

cargo fmt --check result:

Diff in /tmp/rustfmt_bug/src/lib.rs:4:
         looooooooooooooong_field_name: u8,
     }

-
     if None
                                     == Some(Struct {
                                         looooooooooooooong_field_name: 1, 
error[internal]: left behind trailing whitespace
 --> /tmp/rustfmt_bug/src/lib.rs:9:9:74
  |
9 |                                         looooooooooooooong_field_name: 1, 
  |                                                                          ^
  |

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

I don't know if the long field name has anything to do with this, but the comment certainly does, as removing it will make it format correctly.

Removing the trailing space manually will make rustfmt not format but still return with exit code 0.

ytmimi commented 2 months ago

The trailing whitespace issue is a result of not handling comments in binary operators. https://github.com/rust-lang/rustfmt/issues/3591#issuecomment-1190502872. rustfmt leaves the code as is to prevent it from removing the comment. If you remove the comment you'll see that rustfmt properly formats this:

fn fn1() {
    #[derive(PartialEq)]
    struct Struct {
        looooooooooooooong_field_name: u8,
    }

    if None
        == Some(Struct {
            looooooooooooooong_field_name: 1,
        })
        && true
    {
        todo!();
    }
}

Also going to close this one since it's effectively a duplicate of #3591 and #3167