rust-lang / rust-lang/rustfmt

Indentation in closures gets formatted twice and result is not nice™

Open
#4,616 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-closures C-bug only-with-option
Dominant language
Rust
Stars
7k
Forks
1.1k
Avg merge
2d 13h
Merged PRs (30d)
24

Description

Describe the bug

On first invocation of rustfmt closure code gets formatted (nicely, arguably). On any subsequent iteration it gets formatted again (not so nicely, arguably).

To Reproduce

Throw the following in a test.rs file:

#[derive(Debug)]
struct Foo {
  some:   usize,
  member: String,
}

impl Foo {
  pub fn some_fn() {
    let edb_file = fs::read_dir(&event_path)?.find_map(|p| {
      let path = p.ok()?.path();
      (path.is_file() && Self::as_regex().is_match(&get_file_name(&path).ok()?) && path.extension()? == "edb").as_some(path)
    });
  }
}

and put the following in a rustfmt.toml file in the same directory:

# "Block" | "Visual"
indent_style = "Visual"

Now invoke rustfmt on file test.rs once. The following should happen:

#[derive(Debug)]
struct Foo {
    some: usize,
    member: String,
}

impl Foo {
    pub fn some_fn() {
        let edb_file = fs::read_dir(&event_path)?.find_map(|p| {
                           let path = p.ok()?.path();
                           (path.is_file()
                            && Self::as_regex().is_match(&get_file_name(&path).ok()?)
                            && path.extension()? == "edb")
                                                          .as_some(path)
                       });
    }
}

Now invoke rustfmt on file test.rs again, and the following should happen:

#[derive(Debug)]
struct Foo {
    some: usize,
    member: String,
}

impl Foo {
    pub fn some_fn() {
        let edb_file = fs::read_dir(&event_path)?.find_map(|p| {
                                                     let path = p.ok()?.path();
                                                     (path.is_file()
                            && Self::as_regex().is_match(&get_file_name(&path).ok()?)
                            && path.extension()? == "edb")
                                                          .as_some(path)
                                                 });
    }
}

Subsequent invocations should not make a difference. Differing settings for max_width (we use 79 characters) produce similar output.

Expected behavior

rustfmt should certainly not take two invocations to format a section of code. Personally I think the output after the first invocation is the intended one.

Meta

  • rustfmt version: rustfmt 1.4.30-nightly (acd9486 2020-12-20)
  • From where did you install rustfmt?: rustup
  • How do you run rustfmt: through vim but this is reproducible also on direct invocation

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue using test.rs and the adjacent rustfmt.toml with indent_style set to Visual, first running rustfmt once and then again. Compare the two outputs and investigate the formatting path responsible for closure indentation and max_width handling. Done means repeated direct invocations produce identical output, with the first formatted result preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.