rust-lang / rustfmt

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

Chained call after block should be one level deeper #6332

Closed upsuper closed 2 months ago

upsuper commented 2 months ago

Currently code like

    foo.call_some_method().do_something(lots, of, arguments).do_another_thing(also, many, arguments)

gets formatted as

    foo.call_some_method()
        .do_something(lots, of, arguments)
        .do_another_thing(also, many, arguments)

However, something like

    Foo { field_a: value_a, field_b: value_b }.call_some_method().do_something(lots, of, arguments).do_another_thing(also, many, arguments)

gets formatted as

    Foo {
        field_a: value_a,
        field_b: value_b,
    }
    .call_some_method()
    .do_something(lots, of, arguments)
    .do_another_thing(also, many, arguments)

Noting that the chained call is at the same depth as the block above.

This feels inconsistent, and I think it would be good if it can be formatted as

    Foo {
        field_a: value_a,
        field_b: value_b,
    }
        .call_some_method()
        .do_something(lots, of, arguments)
        .do_another_thing(also, many, arguments)

instead, or at least make it configurable.

On a separate note, if this whole thing is wrapped with another block, the formatting is even more weird, for example:

    vec![Foo {
        field_a: value_a,
        field_b: value_b,
    }
    .call_some_method()
    .do_something(lots, of, arguments)
    .do_another_thing(also, many, arguments)]

which I would expect to become something like

    vec![
        Foo {
            field_a: value_a,
            field_b: value_b,
        }
            .call_some_method()
            .do_something(lots, of, arguments)
            .do_another_thing(also, many, arguments),
    ]
ytmimi commented 2 months ago

The struct literal formatting you're highlighting above is consistent with what happens if a chain contains multi-line elements. For example take the following function call:

fn m() {
    bar(
        Some(value_a),
        Some(value_b),
        Some(value_c),
        Some(value_d),
        Some(value_e),
        Some(value_f),
        Some(value_g),
    )
    .call_some_method()
    .do_something(lots, of, arguments)
    .do_another_thing(also, many, arguments)
}
upsuper commented 2 months ago

I'd say that is inconsistent with when it follows a single line as well. Why would the chain get indented when it starts with a single line, but not when it starts with a multi-line block?

ytmimi commented 2 months ago

Got a response to my question in https://github.com/rust-lang/style-team/issues/195#issuecomment-2368749866, and there's nothing to change on the rustfmt side.