From 80a02793f54d44fa3cf86766623bfca57afdea70 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Wed, 19 Apr 2023 19:59:33 -0500 Subject: [PATCH] docs(style): add let-chain style rules --- src/doc/style-guide/src/expressions.md | 81 +++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 96f66c89c259f..b954ea2f4b8c6 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -485,8 +485,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`). The keyword, any initial clauses, and the opening brace of the block should be on a single line. The usual rules for [block formatting](#blocks) should be @@ -512,10 +515,11 @@ if let ... { } ``` -If the control line needs to be broken, then prefer to break before the `=` in -`* let` expressions 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: +If the control line needs to be broken, then prefer breaking before 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) @@ -536,6 +540,70 @@ 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_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, separated by `&&`, with the first being an +`ident` (which can optionally be preceded by any number of unary prefix operators) +and the second 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() { + // ... +} + +let operator = if !from_hir_call && let Some(p) = parent { + // ... +} + +if a + || let Some(b) = foo() +{ + // .. +} + +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 is multi-lined and ends with one or more closing @@ -554,7 +622,6 @@ if !self.config.file_lines().intersects( } ``` - #### Single line `if else` Formatters may place an `if else` or `if let else` on a single line if it occurs