Skip to content

Commit 19a5344

Browse files
committed
Reapply "Add let_chains references"
This reverts commit db6fc4e.
1 parent 66e00f7 commit 19a5344

File tree

2 files changed

+112
-70
lines changed

2 files changed

+112
-70
lines changed

Diff for: src/expressions/if-expr.md

+74-53
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
r[expr.if]
2-
# `if` and `if let` expressions
2+
# `if` expressions
33

4-
## `if` expressions
4+
r[expr.if.syntax]
5+
## Syntax
6+
7+
The same syntax is used by `if`, `if let` and chains of expressions.
58

69
r[expr.if.syntax]
710
> **<sup>Syntax</sup>**\
811
> _IfExpression_ :\
9-
> &nbsp;&nbsp; `if` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]\
10-
> &nbsp;&nbsp; (`else` (
11-
> [_BlockExpression_]
12-
> | _IfExpression_
13-
> | _IfLetExpression_ ) )<sup>\?</sup>
12+
> &nbsp;&nbsp; `if` _IfLetList_ [_BlockExpression_]\
13+
> &nbsp;&nbsp; ( `else` _IfLetList_ [_BlockExpression_] )<sup>\?</sup>
14+
>
15+
> _IfLet_ :\
16+
> &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>
17+
> | `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub>
18+
>
19+
> _IfLetList_ :\
20+
> &nbsp;&nbsp; _IfLet_ ( && _IfLet_ )*
21+
22+
r[expr.if.if]
23+
## `if`
1424

1525
r[expr.if.intro]
1626
An `if` expression is a conditional branch in program control.
@@ -53,17 +63,7 @@ assert_eq!(y, "Bigger");
5363
```
5464

5565
r[expr.if.let]
56-
## `if let` expressions
57-
58-
r[expr.if.let.syntax]
59-
> **<sup>Syntax</sup>**\
60-
> _IfLetExpression_ :\
61-
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub>
62-
> [_BlockExpression_]\
63-
> &nbsp;&nbsp; (`else` (
64-
> [_BlockExpression_]
65-
> | _IfExpression_
66-
> | _IfLetExpression_ ) )<sup>\?</sup>
66+
## `if let`
6767

6868
r[expr.if.let.intro]
6969
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.
@@ -115,28 +115,6 @@ let a = if let Some(1) = x {
115115
assert_eq!(a, 3);
116116
```
117117

118-
r[expr.if.let.desugaring]
119-
An `if let` expression is equivalent to a [`match` expression] as follows:
120-
121-
<!-- ignore: expansion example -->
122-
```rust,ignore
123-
if let PATS = EXPR {
124-
/* body */
125-
} else {
126-
/*else */
127-
}
128-
```
129-
130-
is equivalent to
131-
132-
<!-- ignore: expansion example -->
133-
```rust,ignore
134-
match EXPR {
135-
PATS => { /* body */ },
136-
_ => { /* else */ }, // () if there is no else
137-
}
138-
```
139-
140118
r[expr.if.let.or-pattern]
141119
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
142120

@@ -154,30 +132,73 @@ if let E::X(n) | E::Y(n) = v {
154132

155133
r[expr.if.let.lazy-bool]
156134
The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
157-
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_]).
158-
When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below:
135+
Scrutinee expressions also cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with [chains of expressions][_ChainsOfExpressions_].
159136

160-
<!-- ignore: pseudo code -->
161-
```rust,ignore
162-
// Before...
163-
if let PAT = EXPR && EXPR { .. }
137+
r[expr.if.chains]
138+
## Chains of expressions
164139

165-
// After...
166-
if let PAT = ( EXPR && EXPR ) { .. }
140+
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:
167141

168-
// Before...
169-
if let PAT = EXPR || EXPR { .. }
142+
```rust
143+
fn single() {
144+
let outer_opt = Some(Some(1i32));
145+
146+
if let Some(inner_opt) = outer_opt
147+
&& let Some(number) = inner_opt
148+
&& number == 1
149+
{
150+
println!("Peek a boo");
151+
}
152+
}
153+
154+
The above is equivalent to the following without using expression chains:
155+
156+
fn nested() {
157+
let outer_opt = Some(Some(1i32));
158+
159+
if let Some(inner_opt) = outer_opt {
160+
if let Some(number) = inner_opt {
161+
if number == 1 {
162+
println!("Peek a boo");
163+
}
164+
}
165+
}
166+
}
167+
```
168+
169+
In other words, chains are equivalent to nested [`if let` expressions]:
170+
171+
<!-- ignore: expansion example -->
172+
```rust,ignore
173+
if let PAT0 = EXPR0 && let PAT1 = EXPR1 {
174+
/* body */
175+
} else {
176+
/* else */
177+
}
178+
```
179+
180+
is equivalent to
170181

171-
// After...
172-
if let PAT = ( EXPR || EXPR ) { .. }
182+
<!-- ignore: expansion example -->
183+
```rust,ignore
184+
if let PAT0 = EXPR0 {
185+
if let PAT1 = EXPR1 {
186+
/* body */
187+
}
188+
else {
189+
/* else */
190+
}
191+
} else {
192+
/* else */
193+
}
173194
```
174195

175196
[_BlockExpression_]: block-expr.md
197+
[_ChainsOfExpressions_]: #chains-of-expressions
176198
[_Expression_]: ../expressions.md
177199
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
178200
[_Pattern_]: ../patterns.md
179201
[_Scrutinee_]: match-expr.md
180-
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
181202
[`match` expression]: match-expr.md
182203
[boolean type]: ../types/boolean.md
183204
[scrutinee]: ../glossary.md#scrutinee

Diff for: src/expressions/loop-expr.md

+38-17
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ r[expr.loop.syntax]
77
> &nbsp;&nbsp; [_LoopLabel_]<sup>?</sup> (\
88
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_InfiniteLoopExpression_]\
99
> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicateLoopExpression_]\
10-
> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicatePatternLoopExpression_]\
1110
> &nbsp;&nbsp; &nbsp;&nbsp; | [_IteratorLoopExpression_]\
1211
> &nbsp;&nbsp; &nbsp;&nbsp; | [_LabelBlockExpression_]\
1312
> &nbsp;&nbsp; )
1413
1514
[_LoopLabel_]: #loop-labels
1615
[_InfiniteLoopExpression_]: #infinite-loops
1716
[_PredicateLoopExpression_]: #predicate-loops
18-
[_PredicatePatternLoopExpression_]: #predicate-pattern-loops
1917
[_IteratorLoopExpression_]: #iterator-loops
2018
[_LabelBlockExpression_]: #labelled-block-expressions
2119

@@ -59,16 +57,22 @@ r[expr.loop.while]
5957
## Predicate loops
6058

6159
r[expr.loop.while.syntax]
62-
> **<sup>Syntax</sup>**\
63-
> _PredicateLoopExpression_ :\
64-
> &nbsp;&nbsp; `while` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]
60+
### Syntax
6561

66-
r[expr.loop.while.intro]
67-
A `while` loop begins by evaluating the [boolean] loop conditional operand.
62+
r[expr.loop.while.syntax.intro]
63+
The same syntax is used by `while`, `while let` and chains of expressions.
6864

69-
r[expr.loop.while.condition]
70-
If the loop conditional operand evaluates to `true`, the loop body block executes, then control returns to the loop conditional operand.
71-
If the loop conditional expression evaluates to `false`, the `while` expression completes.
65+
> **<sup>Syntax</sup>**\
66+
> [_PredicateLoopExpression_] :\
67+
> _WhileExpression_ :\
68+
> &nbsp;&nbsp; `while` _WhileLetList_ [_BlockExpression_]
69+
>
70+
> _WhileLet_ :\
71+
> &nbsp;&nbsp; ( [_Expression_]<sub>_except struct expression_</sub>
72+
> | `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub> )
73+
>
74+
> _WhileLetList_ :\
75+
> &nbsp;&nbsp; _WhileLet_ ( && _WhileLet_ )*
7276
7377
An example:
7478

@@ -82,13 +86,7 @@ while i < 10 {
8286
```
8387

8488
r[expr.loop.while.let]
85-
## Predicate pattern loops
86-
87-
r[expr.loop.while.let.syntax]
88-
> **<sup>Syntax</sup>**\
89-
> [_PredicatePatternLoopExpression_] :\
90-
> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub>
91-
> [_BlockExpression_]
89+
## `while let`
9290

9391
r[expr.loop.while.let.intro]
9492
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.
@@ -147,6 +145,29 @@ while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
147145
r[expr.loop.while.let.lazy-bool]
148146
As is the case in [`if let` expressions], the scrutinee cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
149147

148+
r[expr.loop.while.chains]
149+
### Chains of expressions
150+
151+
r[expr.loop.while.chains.intro]
152+
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:
153+
154+
```rust
155+
fn main() {
156+
let outer_opt = Some(Some(1i32));
157+
158+
while let Some(inner_opt) = outer_opt
159+
&& let Some(number) = inner_opt
160+
&& number == 1
161+
{
162+
println!("Peek a boo");
163+
break;
164+
}
165+
}
166+
```
167+
168+
r[expr.loop.while.chains.limits]
169+
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.
170+
150171
r[expr.loop.for]
151172
## Iterator loops
152173

0 commit comments

Comments
 (0)