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

Document if_while_or_patterns #516

Merged
merged 3 commits into from
Jan 27, 2019
Merged
Show file tree
Hide file tree
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
28 changes: 22 additions & 6 deletions src/expressions/if-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ assert_eq!(y, "Bigger");

> **<sup>Syntax</sup>**\
> _IfLetExpression_ :\
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
> &nbsp;&nbsp; `if` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
> [_BlockExpression_]\
> &nbsp;&nbsp; (`else` (
> [_BlockExpression_]
Expand Down Expand Up @@ -95,10 +95,10 @@ let a = if let Some(1) = x {
assert_eq!(a, 3);
```

An `if let` expression is equivalent to a `match` expression as follows:
An `if let` expression is equivalent to a [`match` expression] as follows:

```rust,ignore
if let PAT = EXPR {
if let PATS = EXPR {
/* body */
} else {
/*else */
Expand All @@ -109,11 +109,26 @@ is equivalent to

```rust,ignore
match EXPR {
PAT => { /* body */ },
PATS => { /* body */ },
_ => { /* else */ }, // () if there is no else
}
```

Multiple patterns may be specified with the `|` operator. This has the same semantics
Centril marked this conversation as resolved.
Show resolved Hide resolved
as with `|` in `match` expressions:

```rust
enum E {
X(u8),
Y(u8),
Z(u8),
}
let v = E::Y(12);
if let E::X(n) | E::Y(n) = v {
assert_eq!(n, 12);
}
```

The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
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_]).
Expand All @@ -134,9 +149,10 @@ if let PAT = EXPR || EXPR { .. }
if let PAT = ( EXPR || EXPR ) { .. }
```

[_Expression_]: expressions.html
[_BlockExpression_]: expressions/block-expr.html
[_Pattern_]: patterns.html
[_Expression_]: expressions.html
[_LazyBooleanOperatorExpression_]: expressions/operator-expr.html#lazy-boolean-operators
[_MatchArmPatterns_]: expressions/match-expr.html
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
[`match` expression]: expressions/match-expr.html
[scrutinee]: glossary.html#scrutinee
32 changes: 21 additions & 11 deletions src/expressions/loop-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ while i < 10 {

> **<sup>Syntax</sup>**\
> [_PredicatePatternLoopExpression_] :\
> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Expression_]<sub>except struct expression</sub>
> &nbsp;&nbsp; `while` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>except struct expression</sub>
> [_BlockExpression_]

A `while let` loop is semantically similar to a `while` loop but in place of a
Expand All @@ -90,11 +90,11 @@ while let _ = 5 {
}
```

A `while let` loop is equivalent to a `loop` expression containing a `match`
expression as follows.
A `while let` loop is equivalent to a `loop` expression containing a [`match`
expression] as follows.

```rust,ignore
'label: while let PAT = EXPR {
'label: while let PATS = EXPR {
/* loop body */
}
```
Expand All @@ -104,12 +104,23 @@ is equivalent to
```rust,ignore
'label: loop {
match EXPR {
PAT => { /* loop body */ },
PATS => { /* loop body */ },
_ => break,
}
}
```

Multiple patterns may be specified with the `|` operator. This has the same semantics
Centril marked this conversation as resolved.
Show resolved Hide resolved
as with `|` in `match` expressions:

```rust
let mut vals = vec![2, 3, 1, 2, 2];
while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
// Prints 2, 2, then 1
println!("{}", v);
}
```

## Iterator loops

> **<sup>Syntax</sup>**\
Expand Down Expand Up @@ -272,12 +283,11 @@ and the `loop` must have a type compatible with each `break` expression.
expression `()`.

[IDENTIFIER]: identifiers.html
[temporary values]: expressions.html#temporary-lifetimes

[_Expression_]: expressions.html
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
[_BlockExpression_]: expressions/block-expr.html
[_Expression_]: expressions.html
[_MatchArmPatterns_]: expressions/match-expr.html
[_Pattern_]: patterns.html

[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels

[`match` expression]: expressions/match-expr.html
[scrutinee]: glossary.html#scrutinee
[temporary values]: expressions.html#temporary-lifetimes
36 changes: 23 additions & 13 deletions src/expressions/match-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ match x {
Variables bound within the pattern are scoped to the match guard and the arm's
expression. The [binding mode] (move, copy, or reference) depends on the pattern.

Multiple match patterns may be joined with the `|` operator:
Multiple match patterns may be joined with the `|` operator. Each pattern will be
tested in left-to-right sequence until a successful match is found.
Centril marked this conversation as resolved.
Show resolved Hide resolved

```rust
# let x = 9;
Expand All @@ -73,19 +74,30 @@ let message = match x {
};

assert_eq!(message, "a few");

// Demonstration of pattern match order.
struct S(i32, i32);

match S(1, 2) {
S(z @ 1, _) | S(_, z @ 2) => assert_eq!(z, 1),
_ => panic!(),
}
```

Please notice that the `2..=9` is a [Range Pattern], not a [Range Expression]
and, thus, only those types of ranges supported by range patterns can be used
in match arms.
> Note: The `2..=9` is a [Range Pattern], not a [Range Expression]. Thus, only
> those types of ranges supported by range patterns can be used in match arms.

Every binding in each `|` separated pattern must appear in all of the patterns
in the arm. Every binding of the same name must have the same type, and have
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit vague since it doesn't say whether "same type" accounts for subtyping or not, but it's serviceable until we have a more formal semantics.

the same binding mode.

Match arms can accept _match guards_ to further refine the
criteria for matching a case. Pattern guards appear after the pattern and
consist of a bool-typed expression following the `if` keyword. A pattern guard
may refer to the variables bound within the pattern they follow.

When the pattern matches successfully, the pattern guard expression is executed.
If the expression is truthy, the pattern is successfully matched against.
If the expression evaluates to true, the pattern is successfully matched against.
Otherwise, the next pattern, including other matches with the `|` operator in
the same arm, is tested.

Expand All @@ -104,15 +116,13 @@ let message = match maybe_digit {
> and side effects it has to execute multiple times. For example:
>
> ```rust
> use std::cell::Cell;
> fn main() {
> let i : Cell<i32> = Cell::new(0);
> match 1 {
> 1 | _ if { i.set(i.get() + 1); false } => {}
> _ => {}
> }
> assert_eq!(i.get(), 2);
> # use std::cell::Cell;
> let i : Cell<i32> = Cell::new(0);
> match 1 {
> 1 | _ if { i.set(i.get() + 1); false } => {}
> _ => {}
> }
> assert_eq!(i.get(), 2);
> ```

## Attributes on match arms
Expand Down