Skip to content

Commit 8d28c49

Browse files
authored
Merge pull request #1251 from compiler-errors/revert-let-chains
Revert let chains reference docs
2 parents e1dc762 + db6fc4e commit 8d28c49

13 files changed

+129
-145
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

+81-75
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
1-
# `if` expressions
1+
# `if` and `if let` expressions
22

3-
## Syntax
3+
## `if` expressions
44

55
> **<sup>Syntax</sup>**\
66
> _IfExpression_ :\
7-
> &nbsp;&nbsp; `if` _IfConditions_ [_BlockExpression_]\
8-
> &nbsp;&nbsp; (`else` ( [_BlockExpression_] | _IfExpression_ ) )<sup>\?</sup>
9-
>
10-
> _IfConditions_ :\
11-
> &nbsp;&nbsp; _IfCondition_ ( && _IfCondition_ )*
12-
>
13-
> _IfCondition_ :\
14-
> &nbsp;&nbsp; &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>\
15-
> &nbsp;&nbsp; | `let` [_Pattern_] `=` [_Scrutinee_]
7+
> &nbsp;&nbsp; `if` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]\
8+
> &nbsp;&nbsp; (`else` (
9+
> [_BlockExpression_]
10+
> | _IfExpression_
11+
> | _IfLetExpression_ ) )<sup>\?</sup>
1612
1713
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.
14+
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.
15+
The condition operands must have the [boolean type].
16+
If a condition operand evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped.
17+
If a condition operand evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated.
2618
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.
19+
An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
2920
An `if` expression must have the same type in all situations.
3021

3122
```rust
@@ -38,7 +29,6 @@ if x == 4 {
3829
println!("x is something else");
3930
}
4031

41-
// `if` can be used as an expression.
4232
let y = if 12 * 15 > 150 {
4333
"Bigger"
4434
} else {
@@ -47,23 +37,34 @@ let y = if 12 * 15 > 150 {
4737
assert_eq!(y, "Bigger");
4838
```
4939

50-
## `if let` patterns
40+
## `if let` expressions
5141

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:
42+
> **<sup>Syntax</sup>**\
43+
> _IfLetExpression_ :\
44+
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub>
45+
> [_BlockExpression_]\
46+
> &nbsp;&nbsp; (`else` (
47+
> [_BlockExpression_]
48+
> | _IfExpression_
49+
> | _IfLetExpression_ ) )<sup>\?</sup>
50+
51+
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.
52+
If the value of the scrutinee matches the pattern, the corresponding block will execute.
53+
Otherwise, flow proceeds to the following `else` block if it exists.
54+
Like `if` expressions, `if let` expressions have a value determined by the block that is evaluated.
5455

5556
```rust
5657
let dish = ("Ham", "Eggs");
5758

58-
// This body will be skipped because the pattern is refuted.
59+
// this body will be skipped because the pattern is refuted
5960
if let ("Bacon", b) = dish {
6061
println!("Bacon is served with {}", b);
6162
} else {
6263
// This block is evaluated instead.
6364
println!("No bacon will be served");
6465
}
6566

66-
// This body will execute.
67+
// this body will execute
6768
if let ("Ham", b) = dish {
6869
println!("Ham is served with {}", b);
6970
}
@@ -73,8 +74,44 @@ if let _ = 5 {
7374
}
7475
```
7576

76-
Multiple patterns may be specified with the `|` operator.
77-
This has the same semantics as with `|` in [`match` expressions]:
77+
`if` and `if let` expressions can be intermixed:
78+
79+
```rust
80+
let x = Some(3);
81+
let a = if let Some(1) = x {
82+
1
83+
} else if x == Some(2) {
84+
2
85+
} else if let Some(y) = x {
86+
y
87+
} else {
88+
-1
89+
};
90+
assert_eq!(a, 3);
91+
```
92+
93+
An `if let` expression is equivalent to a [`match` expression] as follows:
94+
95+
<!-- ignore: expansion example -->
96+
```rust,ignore
97+
if let PATS = EXPR {
98+
/* body */
99+
} else {
100+
/*else */
101+
}
102+
```
103+
104+
is equivalent to
105+
106+
<!-- ignore: expansion example -->
107+
```rust,ignore
108+
match EXPR {
109+
PATS => { /* body */ },
110+
_ => { /* else */ }, // () if there is no else
111+
}
112+
```
113+
114+
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
78115

79116
```rust
80117
enum E {
@@ -88,62 +125,31 @@ if let E::X(n) | E::Y(n) = v {
88125
}
89126
```
90127

91-
## Chains of conditions
92-
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.
98-
99-
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:
100-
101-
```rust
102-
fn single() {
103-
let outer_opt = Some(Some(1i32));
104-
105-
if let Some(inner_opt) = outer_opt
106-
&& let Some(number) = inner_opt
107-
&& number == 1
108-
{
109-
println!("Peek a boo");
110-
}
111-
}
112-
```
128+
The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
129+
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_]).
130+
When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below:
113131

114-
The above is equivalent to the following without using chains of conditions:
132+
<!-- ignore: psuedo code -->
133+
```rust,ignore
134+
// Before...
135+
if let PAT = EXPR && EXPR { .. }
115136
116-
```rust
117-
fn nested() {
118-
let outer_opt = Some(Some(1i32));
119-
120-
if let Some(inner_opt) = outer_opt {
121-
if let Some(number) = inner_opt {
122-
if number == 1 {
123-
println!("Peek a boo");
124-
}
125-
}
126-
}
127-
}
128-
```
137+
// After...
138+
if let PAT = ( EXPR && EXPR ) { .. }
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+
// Before...
141+
if let PAT = EXPR || EXPR { .. }
132142
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) { /*...*/ }
143+
// After...
144+
if let PAT = ( EXPR || EXPR ) { .. }
139145
```
140146

141-
142147
[_BlockExpression_]: block-expr.md
143148
[_Expression_]: ../expressions.md
144149
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
145150
[_Pattern_]: ../patterns.md
146151
[_Scrutinee_]: match-expr.md
147-
[`match` expressions]: match-expr.md
152+
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
153+
[`match` expression]: match-expr.md
148154
[boolean type]: ../types/boolean.md
149155
[scrutinee]: ../glossary.md#scrutinee

0 commit comments

Comments
 (0)