diff --git a/src/expressions/if-expr.md b/src/expressions/if-expr.md
index 591437fc9..6443d9fe9 100644
--- a/src/expressions/if-expr.md
+++ b/src/expressions/if-expr.md
@@ -1,14 +1,22 @@
-# `if` and `if let` expressions
+# `if` expressions
-## `if` expressions
+## Syntax
+
+The same syntax is used by `if`, `if let` and chains of expressions.
> **Syntax**\
> _IfExpression_ :\
-> `if` [_Expression_]_except struct expression_ [_BlockExpression_]\
-> (`else` (
-> [_BlockExpression_]
-> | _IfExpression_
-> | _IfLetExpression_ ) )\?
+> `if` _IfLetList_ [_BlockExpression_]\
+> ( `else` _IfLetList_ [_BlockExpression_] )\?
+>
+> _IfLet_ :\
+> [_Expression_]_except struct expression_
+> | `let` [_Pattern_] `=` [_Expression_]_except struct expression_
+>
+> _IfLetList_ :\
+> _IfLet_ ( && _IfLet_ )*
+
+## `if`
An `if` expression is a conditional branch in program control.
The syntax of an `if` expression is a condition operand, followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
@@ -37,16 +45,7 @@ let y = if 12 * 15 > 150 {
assert_eq!(y, "Bigger");
```
-## `if let` expressions
-
-> **Syntax**\
-> _IfLetExpression_ :\
-> `if` `let` [_Pattern_] `=` [_Scrutinee_]_except lazy boolean operator expression_
-> [_BlockExpression_]\
-> (`else` (
-> [_BlockExpression_]
-> | _IfExpression_
-> | _IfLetExpression_ ) )\?
+## `if let`
An `if let` expression is semantically similar to an `if` expression but in place of a condition operand it expects the keyword `let` followed by a pattern, an `=` and a [scrutinee] operand.
If the value of the scrutinee matches the pattern, the corresponding block will execute.
@@ -90,27 +89,6 @@ let a = if let Some(1) = x {
assert_eq!(a, 3);
```
-An `if let` expression is equivalent to a [`match` expression] as follows:
-
-
-```rust,ignore
-if let PATS = EXPR {
- /* body */
-} else {
- /*else */
-}
-```
-
-is equivalent to
-
-
-```rust,ignore
-match EXPR {
- PATS => { /* body */ },
- _ => { /* else */ }, // () if there is no else
-}
-```
-
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
```rust
@@ -125,31 +103,72 @@ if let E::X(n) | E::Y(n) = v {
}
```
-The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
-Use of a lazy boolean operator is ambiguous with a planned feature change of the language (the implementation of if-let chains - see [eRFC 2947][_eRFCIfLetChain_]).
-When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below:
+The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_]. Scrutinee expressions also cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with [chains of expressions][_ChainsOfExpressions_].
-
-```rust,ignore
-// Before...
-if let PAT = EXPR && EXPR { .. }
+## Chains of expressions
+
+The following is an example of chaining multiple expressions, mixing `let` bindings and boolean expressions, and with expressions able to reference pattern bindings from previous expressions:
-// After...
-if let PAT = ( EXPR && EXPR ) { .. }
+```rust
+fn single() {
+ let outer_opt = Some(Some(1i32));
+
+ if let Some(inner_opt) = outer_opt
+ && let Some(number) = inner_opt
+ && number == 1
+ {
+ println!("Peek a boo");
+ }
+}
+
+The above is equivalent to the following without using expression chains:
+
+fn nested() {
+ let outer_opt = Some(Some(1i32));
+
+ if let Some(inner_opt) = outer_opt {
+ if let Some(number) = inner_opt {
+ if number == 1 {
+ println!("Peek a boo");
+ }
+ }
+ }
+}
+```
+
+In other words, chains are equivalent to nested [`if let` expressions]:
+
+
+```rust,ignore
+if let PAT0 = EXPR0 && let PAT1 = EXPR1 {
+ /* body */
+} else {
+ /* else */
+}
+```
-// Before...
-if let PAT = EXPR || EXPR { .. }
+is equivalent to
-// After...
-if let PAT = ( EXPR || EXPR ) { .. }
+
+```rust,ignore
+if let PAT0 = EXPR0 {
+ if let PAT1 = EXPR1 {
+ /* body */
+ }
+ else {
+ /* else */
+ }
+} else {
+ /* else */
+}
```
[_BlockExpression_]: block-expr.md
+[_ChainsOfExpressions_]: #chains-of-expressions
[_Expression_]: ../expressions.md
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
[_Pattern_]: ../patterns.md
[_Scrutinee_]: match-expr.md
-[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
[`match` expression]: match-expr.md
[boolean type]: ../types/boolean.md
[scrutinee]: ../glossary.md#scrutinee
diff --git a/src/expressions/loop-expr.md b/src/expressions/loop-expr.md
index 308f3e346..5033a1ce8 100644
--- a/src/expressions/loop-expr.md
+++ b/src/expressions/loop-expr.md
@@ -5,14 +5,12 @@
> [_LoopLabel_]? (\
> [_InfiniteLoopExpression_]\
> | [_PredicateLoopExpression_]\
-> | [_PredicatePatternLoopExpression_]\
> | [_IteratorLoopExpression_]\
> )
[_LoopLabel_]: #loop-labels
[_InfiniteLoopExpression_]: #infinite-loops
[_PredicateLoopExpression_]: #predicate-loops
-[_PredicatePatternLoopExpression_]: #predicate-pattern-loops
[_IteratorLoopExpression_]: #iterator-loops
Rust supports four loop expressions:
@@ -39,9 +37,23 @@ A `loop` expression containing associated [`break` expression(s)](#break-express
## Predicate loops
+### Syntax
+
+The same syntax is used by `while`, `while let` and chains of expressions.
+
> **Syntax**\
-> _PredicateLoopExpression_ :\
-> `while` [_Expression_]_except struct expression_ [_BlockExpression_]
+> [_PredicateLoopExpression_] :\
+> _WhileExpression_ :\
+> `while` _WhileLetList_ [_BlockExpression_]
+>
+> _WhileLet_ :\
+> ( [_Expression_]_except struct expression_
+> | `let` [_Pattern_] `=` [_Expression_]_except struct expression_ )
+>
+> _WhileLetList_ :\
+> _WhileLet_ ( && _WhileLet_ )*
+
+### `while`
A `while` loop begins by evaluating the [boolean] loop conditional operand.
If the loop conditional operand evaluates to `true`, the loop body block executes, then control returns to the loop conditional operand.
@@ -58,13 +70,7 @@ while i < 10 {
}
```
-## Predicate pattern loops
-
-> **Syntax**\
-> [_PredicatePatternLoopExpression_] :\
-> `while` `let` [_Pattern_] `=` [_Scrutinee_]_except lazy boolean operator expression_
-> [_BlockExpression_]
-
+### `while let`
A `while let` loop is semantically similar to a `while` loop but in place of a condition expression it expects the keyword `let` followed by a pattern, an `=`, a [scrutinee] expression and a block expression.
If the value of the scrutinee matches the pattern, the loop body block executes then control returns to the pattern matching statement.
@@ -117,6 +123,26 @@ while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
As is the case in [`if let` expressions], the scrutinee cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
+### Chains of expressions
+
+The following is an example of chaining multiple expressions, mixing `let` bindings and boolean expressions, and with expressions able to reference pattern bindings from previous expressions:
+
+```rust
+fn main() {
+ let outer_opt = Some(Some(1i32));
+
+ while let Some(inner_opt) = outer_opt
+ && let Some(number) = inner_opt
+ && number == 1
+ {
+ println!("Peek a boo");
+ break;
+ }
+}
+```
+
+The only remark is the fact that parenthesis (`while (let Some(a) = opt && (let Some(b) = a)) && b == 1`) and `||` operators (`while let A(x) = e1 || let B(x) = e2`) are not currently supported.
+
## Iterator loops
> **Syntax**\