Skip to content

Commit 4aff5be

Browse files
Revert "Unify while/while let and if/if let expressions."
This reverts commit b83d8e6.
1 parent e1dc762 commit 4aff5be

13 files changed

+121
-91
lines changed

Diff for: src/SUMMARY.md

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

Diff for: src/attributes/type_system.md

+1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ Non-exhaustive types are always considered inhabited in downstream crates.
133133
[_StructExpression_]: ../expressions/struct-expr.md
134134
[_StructPattern_]: ../patterns.md#struct-patterns
135135
[_TupleStructPattern_]: ../patterns.md#tuple-struct-patterns
136+
[`if let`]: ../expressions/if-expr.md#if-let-expressions
136137
[`match`]: ../expressions/match-expr.md
137138
[attributes]: ../attributes.md
138139
[enum]: ../items/enumerations.md

Diff for: src/const_eval.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ to be run.
4545
* pointer to address casts and
4646
* function pointer to address casts.
4747
* Calls of [const functions] and const methods.
48-
* [loop] and [while] expressions.
49-
* [if] and [match] expressions.
48+
* [loop], [while] and [`while let`] expressions.
49+
* [if], [`if let`] and [match] expressions.
5050

5151
## Const context
5252

@@ -121,6 +121,7 @@ Conversely, the following are possible in a const function, but not in a const c
121121
[grouped]: expressions/grouped-expr.md
122122
[interior mutability]: interior-mutability.md
123123
[if]: expressions/if-expr.md#if-expressions
124+
[`if let`]: expressions/if-expr.md#if-let-expressions
124125
[lazy boolean]: expressions/operator-expr.md#lazy-boolean-operators
125126
[let statements]: statements.md#let-statements
126127
[literals]: expressions/literal-expr.md
@@ -137,3 +138,4 @@ Conversely, the following are possible in a const function, but not in a const c
137138
[struct]: expressions/struct-expr.md
138139
[tuple expressions]: expressions/tuple-expr.md
139140
[while]: expressions/loop-expr.md#predicate-loops
141+
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops

Diff for: src/destructors.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,12 @@ variable or field from being dropped automatically.
388388
[tuple expression]: expressions/tuple-expr.md#tuple-expressions
389389

390390
[`for`]: expressions/loop-expr.md#iterator-loops
391-
[`if let`]: expressions/if-expr.md#if-let-patterns
391+
[`if let`]: expressions/if-expr.md#if-let-expressions
392392
[`if`]: expressions/if-expr.md#if-expressions
393393
[`let` statement]: statements.md#let-statements
394394
[`loop`]: expressions/loop-expr.md#infinite-loops
395395
[`match`]: expressions/match-expr.md
396-
[`while let`]: expressions/loop-expr.md#while-let-patterns
396+
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
397397
[`while`]: expressions/loop-expr.md#predicate-loops
398398

399399
[`<T as std::ops::Drop>::drop`]: ../std/ops/trait.Drop.html#tymethod.drop

Diff for: src/expressions.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
> &nbsp;&nbsp; &nbsp;&nbsp; | [_UnsafeBlockExpression_]\
3939
> &nbsp;&nbsp; &nbsp;&nbsp; | [_LoopExpression_]\
4040
> &nbsp;&nbsp; &nbsp;&nbsp; | [_IfExpression_]\
41+
> &nbsp;&nbsp; &nbsp;&nbsp; | [_IfLetExpression_]\
4142
> &nbsp;&nbsp; &nbsp;&nbsp; | [_MatchExpression_]\
4243
> &nbsp;&nbsp; )
4344
@@ -294,13 +295,13 @@ They are never allowed before:
294295
[call expressions]: expressions/call-expr.md
295296
[field]: expressions/field-expr.md
296297
[functional update]: expressions/struct-expr.md#functional-update-syntax
297-
[`if let`]: expressions/if-expr.md#if-let-patterns
298+
[`if let`]: expressions/if-expr.md#if-let-expressions
298299
[match]: expressions/match-expr.md
299300
[method-call]: expressions/method-call-expr.md
300301
[paths]: expressions/path-expr.md
301302
[struct]: expressions/struct-expr.md
302303
[tuple expressions]: expressions/tuple-expr.md
303-
[`while let`]: expressions/loop-expr.md#while-let-patterns
304+
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
304305

305306
[array expressions]: expressions/array-expr.md
306307
[array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions
@@ -347,6 +348,7 @@ They are never allowed before:
347348
[_FieldExpression_]: expressions/field-expr.md
348349
[_GroupedExpression_]: expressions/grouped-expr.md
349350
[_IfExpression_]: expressions/if-expr.md#if-expressions
351+
[_IfLetExpression_]: expressions/if-expr.md#if-let-expressions
350352
[_IndexExpression_]: expressions/array-expr.md#array-and-slice-indexing-expressions
351353
[_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators
352354
[_LiteralExpression_]: expressions/literal-expr.md

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ let a = unsafe { an_unsafe_fn() };
145145
[Inner attributes] are allowed directly after the opening brace of a block expression in the following situations:
146146

147147
* [Function] and [method] bodies.
148-
* Loop bodies ([`loop`], [`while`], and [`for`]).
148+
* Loop bodies ([`loop`], [`while`], [`while let`], and [`for`]).
149149
* Block expressions used as a [statement].
150150
* Block expressions as elements of [array expressions], [tuple expressions],
151151
[call expressions], and tuple-style [struct] expressions.
@@ -172,6 +172,7 @@ fn is_unix_platform() -> bool {
172172
[`loop`]: loop-expr.md#infinite-loops
173173
[`std::ops::Fn`]: ../../std/ops/trait.Fn.html
174174
[`std::future::Future`]: ../../std/future/trait.Future.html
175+
[`while let`]: loop-expr.md#predicate-pattern-loops
175176
[`while`]: loop-expr.md#predicate-loops
176177
[array expressions]: array-expr.md
177178
[call expressions]: call-expr.md

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

+69-43
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,29 @@
22

33
## Syntax
44

5+
The same syntax is used by `if`, `if let` and chains of expressions.
6+
57
> **<sup>Syntax</sup>**\
68
> _IfExpression_ :\
7-
> &nbsp;&nbsp; `if` _IfConditions_ [_BlockExpression_]\
8-
> &nbsp;&nbsp; (`else` ( [_BlockExpression_] | _IfExpression_ ) )<sup>\?</sup>
9+
> &nbsp;&nbsp; `if` _IfLetList_ [_BlockExpression_]\
10+
> &nbsp;&nbsp; ( `else` _IfLetList_ [_BlockExpression_] )<sup>\?</sup>
911
>
10-
> _IfConditions_ :\
11-
> &nbsp;&nbsp; _IfCondition_ ( && _IfCondition_ )*
12+
> _IfLet_ :\
13+
> &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>
14+
> | `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub>
1215
>
13-
> _IfCondition_ :\
14-
> &nbsp;&nbsp; &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>\
15-
> &nbsp;&nbsp; | `let` [_Pattern_] `=` [_Scrutinee_]
16+
> _IfLetList_ :\
17+
> &nbsp;&nbsp; _IfLet_ ( && _IfLet_ )*
18+
19+
## `if`
1620

1721
An `if` expression is a conditional branch in program control.
18-
The syntax of an `if` expression is a sequence of one or more condition operands separated by `&&`,
19-
followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
20-
21-
Condition operands must be either an [_Expression_] with a [boolean type] or a conditional `let` match.
22-
If all of the condition operands evaluate to `true` and all of the `let` patterns successfully match their [scrutinee]s,
23-
the consequent block is executed and any subsequent `else if` or `else` block is skipped.
24-
If any condition operand evaluates to `false` or any `let` pattern does not match its scrutinee,
25-
the consequent block is skipped and any subsequent `else if` condition is evaluated.
22+
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.
23+
The condition operands must have the [boolean type].
24+
If a condition operand evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped.
25+
If a condition operand evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated.
2626
If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed.
27-
28-
An `if` expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
27+
An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
2928
An `if` expression must have the same type in all situations.
3029

3130
```rust
@@ -38,7 +37,6 @@ if x == 4 {
3837
println!("x is something else");
3938
}
4039

41-
// `if` can be used as an expression.
4240
let y = if 12 * 15 > 150 {
4341
"Bigger"
4442
} else {
@@ -47,23 +45,25 @@ let y = if 12 * 15 > 150 {
4745
assert_eq!(y, "Bigger");
4846
```
4947

50-
## `if let` patterns
48+
## `if let`
5149

52-
`let` patterns in an `if` condition allow binding new variables into scope when the pattern matches successfully.
53-
The following examples illustrate bindings using `let` patterns:
50+
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.
51+
If the value of the scrutinee matches the pattern, the corresponding block will execute.
52+
Otherwise, flow proceeds to the following `else` block if it exists.
53+
Like `if` expressions, `if let` expressions have a value determined by the block that is evaluated.
5454

5555
```rust
5656
let dish = ("Ham", "Eggs");
5757

58-
// This body will be skipped because the pattern is refuted.
58+
// this body will be skipped because the pattern is refuted
5959
if let ("Bacon", b) = dish {
6060
println!("Bacon is served with {}", b);
6161
} else {
6262
// This block is evaluated instead.
6363
println!("No bacon will be served");
6464
}
6565

66-
// This body will execute.
66+
// this body will execute
6767
if let ("Ham", b) = dish {
6868
println!("Ham is served with {}", b);
6969
}
@@ -73,8 +73,23 @@ if let _ = 5 {
7373
}
7474
```
7575

76-
Multiple patterns may be specified with the `|` operator.
77-
This has the same semantics as with `|` in [`match` expressions]:
76+
`if` and `if let` expressions can be intermixed:
77+
78+
```rust
79+
let x = Some(3);
80+
let a = if let Some(1) = x {
81+
1
82+
} else if x == Some(2) {
83+
2
84+
} else if let Some(y) = x {
85+
y
86+
} else {
87+
-1
88+
};
89+
assert_eq!(a, 3);
90+
```
91+
92+
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
7893

7994
```rust
8095
enum E {
@@ -88,13 +103,10 @@ if let E::X(n) | E::Y(n) = v {
88103
}
89104
```
90105

91-
## Chains of conditions
106+
The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
107+
Scrutinee expressions also cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with [chains of expressions][_ChainsOfExpressions_].
92108

93-
Multiple condition operands can be separated with `&&`.
94-
Similar to a `&&` [_LazyBooleanOperatorExpression_], each operand is evaluated from left-to-right until an operand evaluates as `false` or a `let` match fails,
95-
in which case the subsequent operands are not evaluated.
96-
97-
The bindings of each pattern are put into scope to be available for the next condition operand and the consequent block.
109+
## Chains of expressions
98110

99111
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:
100112

@@ -109,11 +121,9 @@ fn single() {
109121
println!("Peek a boo");
110122
}
111123
}
112-
```
113124

114-
The above is equivalent to the following without using chains of conditions:
125+
The above is equivalent to the following without using expression chains:
115126

116-
```rust
117127
fn nested() {
118128
let outer_opt = Some(Some(1i32));
119129

@@ -127,23 +137,39 @@ fn nested() {
127137
}
128138
```
129139

130-
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.
131-
If a `||` expression is needed, then parentheses can be used. For example:
140+
In other words, chains are equivalent to nested [`if let` expressions]:
132141

133-
```rust
134-
# let foo = Some(123);
135-
# let condition1 = true;
136-
# let condition2 = false;
137-
// Parentheses are required here.
138-
if let Some(x) = foo && (condition1 || condition2) { /*...*/ }
142+
<!-- ignore: expansion example -->
143+
```rust,ignore
144+
if let PAT0 = EXPR0 && let PAT1 = EXPR1 {
145+
/* body */
146+
} else {
147+
/* else */
148+
}
139149
```
140150

151+
is equivalent to
152+
153+
<!-- ignore: expansion example -->
154+
```rust,ignore
155+
if let PAT0 = EXPR0 {
156+
if let PAT1 = EXPR1 {
157+
/* body */
158+
}
159+
else {
160+
/* else */
161+
}
162+
} else {
163+
/* else */
164+
}
165+
```
141166

142167
[_BlockExpression_]: block-expr.md
168+
[_ChainsOfExpressions_]: #chains-of-expressions
143169
[_Expression_]: ../expressions.md
144170
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
145171
[_Pattern_]: ../patterns.md
146172
[_Scrutinee_]: match-expr.md
147-
[`match` expressions]: match-expr.md
173+
[`match` expression]: match-expr.md
148174
[boolean type]: ../types/boolean.md
149175
[scrutinee]: ../glossary.md#scrutinee

0 commit comments

Comments
 (0)