Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Amend RFC 2175 to support for loops and leading vert #2530

Merged
merged 1 commit into from
Sep 10, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 66 additions & 18 deletions text/2175-if-while-or-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
[`if let`]: https://github.com/rust-lang/rfcs/pull/160
[`while let`]: https://github.com/rust-lang/rfcs/pull/214

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

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

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

// Only possible when `L = T` such that `kind : ParameterKind<T, T>`.
let Ty(x) | Lifetime(x) = kind;

for Ty(x) | Lifetime(x) in ::std::iter::once(kind);
```

# Motivation
Expand Down Expand Up @@ -136,9 +140,9 @@ loop {

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

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

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

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

For examples, see [motivation].

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

```
if_let_expr : "if" "let" pat [ '|' pat ] * '=' expr '{' block '}'
if_let_expr : "if" "let" '|'? pat [ '|' pat ] * '=' expr '{' block '}'
else_tail ? ;
```

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

```
while_let_expr : [ lifetime ':' ] ? "while" "let" pat [ '|' pat ] * '=' expr '{' block '}' ;
while_let_expr : [ lifetime ':' ] ? "while" "let" '|'? pat [ '|' pat ] * '=' expr '{' block '}' ;
```

### `for`

[for_grammar]: https://github.com/rust-lang/rust/blob/master/src/grammar/parser-lalr.y

The `expr_for` grammar is changed [from][for_grammar]:

```
expr_for : maybe_label FOR pat IN expr_nostruct block ;
```

to:

```
expr_for : maybe_label FOR '|'? pat ('|' pat)* IN expr_nostruct block ;
```

### `let` statements
Expand All @@ -218,12 +238,12 @@ stmt ::= old_stmt_grammar

let_stmt_many ::= "let" pat_two_plus "=" expr ";"

pat_two_plus ::= pat [ '|' pat ] + ;
pat_two_plus ::= '|'? pat [ '|' pat ] + ;
```

## Syntax lowering

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

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

Source:
```rust
if let PAT [| PAT]* = EXPR { BODY }
if let |? PAT [| PAT]* = EXPR { BODY }
```
Result:
```rust
Expand All @@ -251,7 +271,7 @@ match EXPR {

Source:
```rust
if let PAT [| PAT]* = EXPR { BODY_IF } else { BODY_ELSE }
if let |? PAT [| PAT]* = EXPR { BODY_IF } else { BODY_ELSE }
```
Result:
```rust
Expand All @@ -265,7 +285,7 @@ Source:
```rust
if COND {
BODY_IF
} else if let PAT [| PAT]* = EXPR {
} else if let |? PAT [| PAT]* = EXPR {
BODY_ELSE_IF
} else {
BODY_ELSE
Expand All @@ -277,15 +297,15 @@ if COND {
BODY_IF
} else {
match EXPR {
PAT [| PAT]* => { BODY_ELSE_IF }
|? PAT [| PAT]* => { BODY_ELSE_IF }
_ => { BODY_ELSE }
}
}
```

Source
```rust
if let PAT [| PAT]* = EXPR {
if let |? PAT [| PAT]* = EXPR {
BODY_IF
} else if COND {
BODY_ELSE_IF_1
Expand All @@ -296,7 +316,7 @@ if let PAT [| PAT]* = EXPR {
Result:
```rust
match EXPR {
PAT [| PAT]* => { BODY_IF }
|? PAT [| PAT]* => { BODY_IF }
_ if COND => { BODY_ELSE_IF_1 }
_ if OTHER_COND => { BODY_ELSE_IF_2 }
_ => {}
Expand All @@ -311,7 +331,7 @@ The following example is an extension on the [`while let` RFC].

Source
```rust
['label:] while let PAT [| PAT]* = EXPR {
['label:] while let |? PAT [| PAT]* = EXPR {
BODY
}
```
Expand All @@ -325,6 +345,34 @@ Result:
}
```

### Examples, `for`

Assuming that the semantics of `for` is defined by a desugaring from:

```rust
for PAT in EXPR_ITER {
BODY
}
```

into:

```rust
match IntoIterator::into_iter(EXPR_ITER) {
mut iter => loop {
let next = match iter.next() {
Some(val) => val,
None => break,
};
let PAT = next;
{ BODY };
},
};
```

then the only thing that changes is that `PAT` may include `|` at the top level
in the `for` loop and the desugaring as per the section on grammar.

## Desugaring `let` statements with `|` in the top-level pattern

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

Another alternative is to only deal with `if/while let` expressions but not
`let` statements.
`let` and `for` statements.

# Unresolved questions
[unresolved]: #unresolved-questions
Expand Down