Rollup merge of #139456 - calebcartwright:style-let-chains-final, r=joshtriplett

style guide: add let-chain rules

Reopens #110568

refs #53667 and I suppose #132833 as well

This reflects the style rules that the style team had already agreed upon back in 2023, with the addition of literals in the lhs being permissible for single line formatting, and the removal of unnecessary language/example snippets around non-`&&` operators that was a small hiccup in the original PR.

It also reflects current formatting behavior implemented in rustfmt (though note that the adjustment to include literals has been implemented & merged, but is still pending a sync to nightly)
This commit is contained in:
Jakub Beránek 2025-04-07 08:23:35 +02:00 committed by GitHub
commit 1b8dbda9c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -521,8 +521,11 @@ self.pre_comment.as_ref().map_or(
## Control flow expressions
This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
expressions.
This section covers `for` and `loop` expressions, as well as `if` and `while`
expressions with their sub-expression variants. This includes those with a
single `let` sub-expression (i.e. `if let` and `while let`)
as well as "let-chains": those with one or more `let` sub-expressions and
one or more bool-type conditions (i.e. `if a && let Some(b) = c`).
Put the keyword, any initial clauses, and the opening brace of the block all on
a single line, if they fit. Apply the usual rules for [block
@ -548,10 +551,11 @@ if let ... {
}
```
If the control line needs to be broken, prefer to break before the `=` in `*
let` expressions and before `in` in a `for` expression; block-indent the
following line. If the control line is broken for any reason, put the opening
brace on its own line, not indented. Examples:
If the control line needs to be broken, then prefer breaking after the `=` for any
`let` sub-expression in an `if` or `while` expression that does not fit,
and before `in` in a `for` expression; the following line should be block indented.
If the control line is broken for any reason, then the opening brace should be on its
own line and not indented. Examples:
```rust
while let Some(foo)
@ -572,6 +576,68 @@ if a_long_expression
{
...
}
if let Some(a) = b
&& another_long_expression
&& a_third_long_expression
{
// ...
}
if let Some(relatively_long_thing)
= a_long_expression
&& another_long_expression
&& a_third_long_expression
{
// ...
}
if some_expr
&& another_long_expression
&& let Some(relatively_long_thing) =
a_long_long_long_long_long_long_really_reallllllllllyyyyyyy_long_expression
&& a_third_long_expression
{
// ...
}
```
A let-chain control line is allowed to be formatted on a single line provided
it only consists of two clauses, with the first, left-hand side operand being a literal or an
`ident` (which can optionally be preceded by any number of unary prefix operators),
and the second, right-hand side operand being a single-line `let` clause. Otherwise,
the control line must be broken and formatted according to the above rules. For example:
```rust
if a && let Some(b) = foo() {
// ...
}
if true && let Some(b) = foo() {
// ...
}
let operator = if !from_hir_call && let Some(p) = parent {
// ...
};
if let Some(b) = foo()
&& a
{
// ..
}
if foo()
&& let Some(b) = bar
{
// ...
}
if gen_pos != GenericArgPosition::Type
&& let Some(b) = gen_args.bindings.first()
{
// ..
}
```
Where the initial clause spans multiple lines and ends with one or more closing