Skip to content

Commit 1c51119

Browse files
authored
Merge pull request #2530 from Centril/fix/if-while-or-patterns
Amend RFC 2175 to support for loops and leading vert
2 parents 26a847f + ca9959e commit 1c51119

File tree

1 file changed

+66
-18
lines changed

1 file changed

+66
-18
lines changed

text/2175-if-while-or-patterns.md

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
[`if let`]: https://github.com/rust-lang/rfcs/pull/160
1010
[`while let`]: https://github.com/rust-lang/rfcs/pull/214
1111

12-
Enables "or" patterns for [`if let`] and [`while let`] expressions as well as
13-
`let` statements. In other words, examples like the following are now possible:
12+
Enables "or" patterns for [`if let`] and [`while let`] expressions
13+
as well as `let` and `for` statements. In other words,
14+
examples like the following are now possible:
1415

1516
```rust
1617
enum E<T> {
@@ -28,9 +29,12 @@ while let A(x) | B(x) = source() {
2829
}
2930

3031
enum ParameterKind<T, L = T> { Ty(T), Lifetime(L), }
32+
use ParameterKind::*;
3133

3234
// Only possible when `L = T` such that `kind : ParameterKind<T, T>`.
3335
let Ty(x) | Lifetime(x) = kind;
36+
37+
for Ty(x) | Lifetime(x) in ::std::iter::once(kind);
3438
```
3539

3640
# Motivation
@@ -136,9 +140,9 @@ loop {
136140

137141
Another major motivation of the RFC is consistency with `match`.
138142

139-
To keep `let` statements consistent with `if let`, and to enable the scenario
140-
exemplified by `ParameterKind` in the [motivation], these or-patterns are
141-
allowed at the top level of `let` statements.
143+
To keep `let` and `for` statements consistent with `if let`,
144+
and to enable the scenario exemplified by `ParameterKind` in the [motivation],
145+
these or-patterns are allowed at the top level of `let` and `for` statements.
142146

143147
In addition to the `ParameterKind` example, we can also consider
144148
`slice.binary_search(&x)`. If we are only interested in the `index` at where
@@ -165,7 +169,7 @@ words: cover all cases, be exhaustive, this is not the case (currently) with
165169
This RFC does not change this.
166170

167171
The RFC only extends the use of or-patterns at the top level from `match`es
168-
to `if let` and `while let` expressions as well as `let` statements.
172+
to `if let` and `while let` expressions as well as `let` and `for` statements.
169173

170174
For examples, see [motivation].
171175

@@ -189,7 +193,7 @@ if_let_expr : "if" "let" pat '=' expr '{' block '}'
189193
to:
190194

191195
```
192-
if_let_expr : "if" "let" pat [ '|' pat ] * '=' expr '{' block '}'
196+
if_let_expr : "if" "let" '|'? pat [ '|' pat ] * '=' expr '{' block '}'
193197
else_tail ? ;
194198
```
195199

@@ -204,7 +208,23 @@ while_let_expr : [ lifetime ':' ] ? "while" "let" pat '=' expr '{' block '}' ;
204208
to:
205209

206210
```
207-
while_let_expr : [ lifetime ':' ] ? "while" "let" pat [ '|' pat ] * '=' expr '{' block '}' ;
211+
while_let_expr : [ lifetime ':' ] ? "while" "let" '|'? pat [ '|' pat ] * '=' expr '{' block '}' ;
212+
```
213+
214+
### `for`
215+
216+
[for_grammar]: https://github.com/rust-lang/rust/blob/master/src/grammar/parser-lalr.y
217+
218+
The `expr_for` grammar is changed [from][for_grammar]:
219+
220+
```
221+
expr_for : maybe_label FOR pat IN expr_nostruct block ;
222+
```
223+
224+
to:
225+
226+
```
227+
expr_for : maybe_label FOR '|'? pat ('|' pat)* IN expr_nostruct block ;
208228
```
209229

210230
### `let` statements
@@ -218,12 +238,12 @@ stmt ::= old_stmt_grammar
218238
219239
let_stmt_many ::= "let" pat_two_plus "=" expr ";"
220240
221-
pat_two_plus ::= pat [ '|' pat ] + ;
241+
pat_two_plus ::= '|'? pat [ '|' pat ] + ;
222242
```
223243

224244
## Syntax lowering
225245

226-
The changes proposed in this RFC with respect to `if let` and `while let`
246+
The changes proposed in this RFC with respect to `if let`, `while let`, and `for`
227247
can be implemented by transforming the `if/while let` constructs with a
228248
syntax-lowering pass into `match` and `loop` + `match` expressions.
229249

@@ -239,7 +259,7 @@ duplicating any details already specified there.
239259

240260
Source:
241261
```rust
242-
if let PAT [| PAT]* = EXPR { BODY }
262+
if let |? PAT [| PAT]* = EXPR { BODY }
243263
```
244264
Result:
245265
```rust
@@ -251,7 +271,7 @@ match EXPR {
251271

252272
Source:
253273
```rust
254-
if let PAT [| PAT]* = EXPR { BODY_IF } else { BODY_ELSE }
274+
if let |? PAT [| PAT]* = EXPR { BODY_IF } else { BODY_ELSE }
255275
```
256276
Result:
257277
```rust
@@ -265,7 +285,7 @@ Source:
265285
```rust
266286
if COND {
267287
BODY_IF
268-
} else if let PAT [| PAT]* = EXPR {
288+
} else if let |? PAT [| PAT]* = EXPR {
269289
BODY_ELSE_IF
270290
} else {
271291
BODY_ELSE
@@ -277,15 +297,15 @@ if COND {
277297
BODY_IF
278298
} else {
279299
match EXPR {
280-
PAT [| PAT]* => { BODY_ELSE_IF }
300+
|? PAT [| PAT]* => { BODY_ELSE_IF }
281301
_ => { BODY_ELSE }
282302
}
283303
}
284304
```
285305

286306
Source
287307
```rust
288-
if let PAT [| PAT]* = EXPR {
308+
if let |? PAT [| PAT]* = EXPR {
289309
BODY_IF
290310
} else if COND {
291311
BODY_ELSE_IF_1
@@ -296,7 +316,7 @@ if let PAT [| PAT]* = EXPR {
296316
Result:
297317
```rust
298318
match EXPR {
299-
PAT [| PAT]* => { BODY_IF }
319+
|? PAT [| PAT]* => { BODY_IF }
300320
_ if COND => { BODY_ELSE_IF_1 }
301321
_ if OTHER_COND => { BODY_ELSE_IF_2 }
302322
_ => {}
@@ -311,7 +331,7 @@ The following example is an extension on the [`while let` RFC].
311331

312332
Source
313333
```rust
314-
['label:] while let PAT [| PAT]* = EXPR {
334+
['label:] while let |? PAT [| PAT]* = EXPR {
315335
BODY
316336
}
317337
```
@@ -325,6 +345,34 @@ Result:
325345
}
326346
```
327347

348+
### Examples, `for`
349+
350+
Assuming that the semantics of `for` is defined by a desugaring from:
351+
352+
```rust
353+
for PAT in EXPR_ITER {
354+
BODY
355+
}
356+
```
357+
358+
into:
359+
360+
```rust
361+
match IntoIterator::into_iter(EXPR_ITER) {
362+
mut iter => loop {
363+
let next = match iter.next() {
364+
Some(val) => val,
365+
None => break,
366+
};
367+
let PAT = next;
368+
{ BODY };
369+
},
370+
};
371+
```
372+
373+
then the only thing that changes is that `PAT` may include `|` at the top level
374+
in the `for` loop and the desugaring as per the section on grammar.
375+
328376
## Desugaring `let` statements with `|` in the top-level pattern
329377

330378
This is a possible desugaring that a Rust compiler may do.
@@ -371,7 +419,7 @@ It could be claimed that the `if/while let` RFCs already mandate this RFC,
371419
this RFC does answer that question and instead simply mandates it now.
372420

373421
Another alternative is to only deal with `if/while let` expressions but not
374-
`let` statements.
422+
`let` and `for` statements.
375423

376424
# Unresolved questions
377425
[unresolved]: #unresolved-questions

0 commit comments

Comments
 (0)