Skip to content

Commit f23232c

Browse files
committed
Reapply "Unify while/while let and if/if let expressions."
This reverts commit 4aff5be.
1 parent 19955df commit f23232c

13 files changed

+93
-136
lines changed

Diff for: src/SUMMARY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
- [Closure expressions](expressions/closure-expr.md)
6464
- [Loop expressions](expressions/loop-expr.md)
6565
- [Range expressions](expressions/range-expr.md)
66-
- [If and if let expressions](expressions/if-expr.md)
66+
- [If expressions](expressions/if-expr.md)
6767
- [Match expressions](expressions/match-expr.md)
6868
- [Return expressions](expressions/return-expr.md)
6969
- [Await expressions](expressions/await-expr.md)

Diff for: src/attributes/type_system.md

-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ Non-exhaustive types are always considered inhabited in downstream crates.
210210
[_StructExpression_]: ../expressions/struct-expr.md
211211
[_StructPattern_]: ../patterns.md#struct-patterns
212212
[_TupleStructPattern_]: ../patterns.md#tuple-struct-patterns
213-
[`if let`]: ../expressions/if-expr.md#if-let-expressions
214213
[`match`]: ../expressions/match-expr.md
215214
[attributes]: ../attributes.md
216215
[enum]: ../items/enumerations.md

Diff for: src/const_eval.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ r[const-eval.const-expr.const-fn]
102102
* Calls of [const functions] and const methods.
103103

104104
r[const-eval.const-expr.loop]
105-
* [loop], [while] and [`while let`] expressions.
105+
* [loop] and [while] expressions.
106106

107107
r[const-eval.const-expr.if-match]
108-
* [if], [`if let`] and [match] expressions.
108+
* [if] and [match] expressions.
109+
110+
expressions.")
109111

110112
## Const context
111113
[const context]: #const-context
@@ -186,7 +188,6 @@ of whether you are building on a `64` bit or a `32` bit system.
186188
[grouped]: expressions/grouped-expr.md
187189
[interior mutability]: interior-mutability.md
188190
[if]: expressions/if-expr.md#if-expressions
189-
[`if let`]: expressions/if-expr.md#if-let-expressions
190191
[lazy boolean]: expressions/operator-expr.md#lazy-boolean-operators
191192
[let statements]: statements.md#let-statements
192193
[literals]: expressions/literal-expr.md
@@ -203,4 +204,3 @@ of whether you are building on a `64` bit or a `32` bit system.
203204
[struct]: expressions/struct-expr.md
204205
[tuple expressions]: expressions/tuple-expr.md
205206
[while]: expressions/loop-expr.md#predicate-loops
206-
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops

Diff for: src/destructors.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,10 @@ variable or field from being dropped automatically.
473473
[tuple indexing expression]: expressions/tuple-expr.md#tuple-indexing-expressions
474474

475475
[`for`]: expressions/loop-expr.md#iterator-loops
476-
[`if let`]: expressions/if-expr.md#if-let-expressions
476+
[`if let`]: expressions/if-expr.md#if-let-patterns
477477
[`if`]: expressions/if-expr.md#if-expressions
478478
[`let` statement]: statements.md#let-statements
479479
[`loop`]: expressions/loop-expr.md#infinite-loops
480480
[`match`]: expressions/match-expr.md
481-
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
481+
[`while let`]: expressions/loop-expr.md#while-let-patterns
482482
[`while`]: expressions/loop-expr.md#predicate-loops

Diff for: src/expressions.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ r[expr.syntax]
4141
>       | [_UnsafeBlockExpression_]\
4242
>       | [_LoopExpression_]\
4343
>       | [_IfExpression_]\
44-
>       | [_IfLetExpression_]\
4544
>       | [_MatchExpression_]\
4645
>    )
4746
@@ -309,13 +308,13 @@ They are never allowed before:
309308
[call expressions]: expressions/call-expr.md
310309
[field]: expressions/field-expr.md
311310
[functional update]: expressions/struct-expr.md#functional-update-syntax
312-
[`if let`]: expressions/if-expr.md#if-let-expressions
311+
[`if let`]: expressions/if-expr.md#if-let-patterns
313312
[match]: expressions/match-expr.md
314313
[method-call]: expressions/method-call-expr.md
315314
[paths]: expressions/path-expr.md
316315
[struct]: expressions/struct-expr.md
317316
[tuple expressions]: expressions/tuple-expr.md
318-
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
317+
[`while let`]: expressions/loop-expr.md#while-let-patterns
319318

320319
[array expressions]: expressions/array-expr.md
321320
[array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions
@@ -362,7 +361,6 @@ They are never allowed before:
362361
[_FieldExpression_]: expressions/field-expr.md
363362
[_GroupedExpression_]: expressions/grouped-expr.md
364363
[_IfExpression_]: expressions/if-expr.md#if-expressions
365-
[_IfLetExpression_]: expressions/if-expr.md#if-let-expressions
366364
[_IndexExpression_]: expressions/array-expr.md#array-and-slice-indexing-expressions
367365
[_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators
368366
[_LiteralExpression_]: expressions/literal-expr.md

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ r[expr.block.attributes.inner-attributes]
251251
[Inner attributes] are allowed directly after the opening brace of a block expression in the following situations:
252252

253253
* [Function] and [method] bodies.
254-
* Loop bodies ([`loop`], [`while`], [`while let`], and [`for`]).
254+
* Loop bodies ([`loop`], [`while`], and [`for`]).
255255
* Block expressions used as a [statement].
256256
* Block expressions as elements of [array expressions], [tuple expressions],
257257
[call expressions], and tuple-style [struct] expressions.
@@ -278,7 +278,6 @@ fn is_unix_platform() -> bool {
278278
[`for`]: loop-expr.md#iterator-loops
279279
[`loop`]: loop-expr.md#infinite-loops
280280
[`unsafe` blocks]: ../unsafe-keyword.md#unsafe-blocks-unsafe-
281-
[`while let`]: loop-expr.md#predicate-pattern-loops
282281
[`while`]: loop-expr.md#predicate-loops
283282
[array expressions]: array-expr.md
284283
[call expressions]: call-expr.md

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

+42-81
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,38 @@ r[expr.if]
44
r[expr.if.syntax]
55
## Syntax
66

7-
The same syntax is used by `if`, `if let` and chains of expressions.
8-
9-
r[expr.if.syntax]
107
> **<sup>Syntax</sup>**\
118
> _IfExpression_ :\
12-
> &nbsp;&nbsp; `if` _IfLetList_ [_BlockExpression_]\
13-
> &nbsp;&nbsp; ( `else` _IfLetList_ [_BlockExpression_] )<sup>\?</sup>
9+
> &nbsp;&nbsp; `if` _IfConditions_ [_BlockExpression_]\
10+
> &nbsp;&nbsp; (`else` ( [_BlockExpression_] | _IfExpression_ ) )<sup>\?</sup>
1411
>
15-
> _IfLet_ :\
16-
> &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>
17-
> | `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub>
12+
> _IfConditions_ :\
13+
> &nbsp;&nbsp; _IfCondition_ ( && _IfCondition_ )*
1814
>
19-
> _IfLetList_ :\
20-
> &nbsp;&nbsp; _IfLet_ ( && _IfLet_ )*
21-
22-
r[expr.if.if]
23-
## `if`
15+
> _IfCondition_ :\
16+
> &nbsp;&nbsp; &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>\
17+
> &nbsp;&nbsp; | `let` [_Pattern_] `=` [_Scrutinee_]
2418
2519
r[expr.if.intro]
26-
An `if` expression is a conditional branch in program control.
27-
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.
20+
The syntax of an `if` expression is a sequence of one or more condition operands separated by `&&`,
21+
followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
2822

2923
r[expr.if.condition-bool]
30-
The condition operands must have the [boolean type].
24+
Condition operands must be either an [_Expression_] with a [boolean type] or a conditional `let` match.
3125

3226
r[expr.if.condition-true]
33-
If a condition operand evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped.
27+
If all of the condition operands evaluate to `true` and all of the `let` patterns successfully match their [scrutinee]s,
28+
the consequent block is executed and any subsequent `else if` or `else` block is skipped.
3429

3530
r[expr.if.else-if]
36-
If a condition operand evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated.
31+
If any condition operand evaluates to `false` or any `let` pattern does not match its scrutinee,
32+
the consequent block is skipped and any subsequent `else if` condition is evaluated.
3733

3834
r[expr.if.else]
3935
If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed.
4036

4137
r[expr.if.result]
42-
An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
38+
An `if` expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
4339

4440
r[expr.if.type]
4541
An `if` expression must have the same type in all situations.
@@ -54,6 +50,7 @@ if x == 4 {
5450
println!("x is something else");
5551
}
5652

53+
// `if` can be used as an expression.
5754
let y = if 12 * 15 > 150 {
5855
"Bigger"
5956
} else {
@@ -63,32 +60,25 @@ assert_eq!(y, "Bigger");
6360
```
6461

6562
r[expr.if.let]
66-
## `if let`
63+
## `if let` patterns
6764

6865
r[expr.if.let.intro]
69-
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.
70-
71-
r[expr.if.let.pattern]
72-
If the value of the scrutinee matches the pattern, the corresponding block will execute.
66+
`let` patterns in an `if` condition allow binding new variables into scope when the pattern matches successfully.
7367

74-
r[expr.if.let.else]
75-
Otherwise, flow proceeds to the following `else` block if it exists.
76-
77-
r[expr.if.let.result]
78-
Like `if` expressions, `if let` expressions have a value determined by the block that is evaluated.
68+
The following examples illustrate bindings using `let` patterns:
7969

8070
```rust
8171
let dish = ("Ham", "Eggs");
8272

83-
// this body will be skipped because the pattern is refuted
73+
// This body will be skipped because the pattern is refuted.
8474
if let ("Bacon", b) = dish {
8575
println!("Bacon is served with {}", b);
8676
} else {
8777
// This block is evaluated instead.
8878
println!("No bacon will be served");
8979
}
9080

91-
// this body will execute
81+
// This body will execute.
9282
if let ("Ham", b) = dish {
9383
println!("Ham is served with {}", b);
9484
}
@@ -98,25 +88,9 @@ if let _ = 5 {
9888
}
9989
```
10090

101-
r[expr.if.let.else-if]
102-
`if` and `if let` expressions can be intermixed:
103-
104-
```rust
105-
let x = Some(3);
106-
let a = if let Some(1) = x {
107-
1
108-
} else if x == Some(2) {
109-
2
110-
} else if let Some(y) = x {
111-
y
112-
} else {
113-
-1
114-
};
115-
assert_eq!(a, 3);
116-
```
117-
11891
r[expr.if.let.or-pattern]
119-
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
92+
Multiple patterns may be specified with the `|` operator.
93+
This has the same semantics as with `|` in [`match` expressions]:
12094

12195
```rust
12296
enum E {
@@ -130,12 +104,14 @@ if let E::X(n) | E::Y(n) = v {
130104
}
131105
```
132106

133-
r[expr.if.let.lazy-bool]
134-
The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
135-
Scrutinee expressions also cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with [chains of expressions][_ChainsOfExpressions_].
136-
137107
r[expr.if.chains]
138-
## Chains of expressions
108+
## Chains of conditions
109+
110+
Multiple condition operands can be separated with `&&`.
111+
Similar to a `&&` [_LazyBooleanOperatorExpression_], each operand is evaluated from left-to-right until an operand evaluates as `false` or a `let` match fails,
112+
in which case the subsequent operands are not evaluated.
113+
114+
The bindings of each pattern are put into scope to be available for the next condition operand and the consequent block.
139115

140116
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:
141117

@@ -150,9 +126,11 @@ fn single() {
150126
println!("Peek a boo");
151127
}
152128
}
129+
```
153130

154-
The above is equivalent to the following without using expression chains:
131+
The above is equivalent to the following without using chains of conditions:
155132

133+
```rust
156134
fn nested() {
157135
let outer_opt = Some(Some(1i32));
158136

@@ -166,39 +144,22 @@ fn nested() {
166144
}
167145
```
168146

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-
```
147+
If any condition operand is a `let` pattern, then none of the condition operands can be a `||` [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with the `let` scrutinee.
148+
If a `||` expression is needed, then parentheses can be used. For example:
179149

180-
is equivalent to
181-
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-
}
150+
```rust
151+
# let foo = Some(123);
152+
# let condition1 = true;
153+
# let condition2 = false;
154+
// Parentheses are required here.
155+
if let Some(x) = foo && (condition1 || condition2) { /*...*/ }
194156
```
195157

196158
[_BlockExpression_]: block-expr.md
197-
[_ChainsOfExpressions_]: #chains-of-expressions
198159
[_Expression_]: ../expressions.md
199160
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
200161
[_Pattern_]: ../patterns.md
201162
[_Scrutinee_]: match-expr.md
202-
[`match` expression]: match-expr.md
163+
[`match` expressions]: match-expr.md
203164
[boolean type]: ../types/boolean.md
204165
[scrutinee]: ../glossary.md#scrutinee

0 commit comments

Comments
 (0)