Skip to content

Commit 8b63437

Browse files
committed
rewrite parsing section for clarity
1 parent be09503 commit 8b63437

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

text/3637-guard-patterns.md

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,29 +76,43 @@ x @ A(..) if pred <=> (x @ A(..)) if pred
7676
A(..) | B(..) if pred <=> (A(..) | B(..)) if pred
7777
```
7878

79-
## Interaction with Expression Operators
79+
## Precedence Relative to `|`
8080

81-
The or-pattern operator and the bitwise OR operator both use the `|` token. This creates a parsing ambiguity:
81+
Consider the following match expression:
8282

8383
```rust
84-
// How is this parsed?
85-
false if foo | true
86-
// As a guard pattern nested in an or-pattern?
87-
(false if foo) | true
88-
// Or as a pattern guarded by a bitwise OR operation?
89-
false if (foo | true)
84+
match foo {
85+
A | B if c | d => {},
86+
}
87+
```
88+
89+
This match arm is currently parsed as `(A | B) if (c | d)`, with the first `|` being the or-operator on patterns and the second being the bitwise OR operator on expressions. Therefore, to maintain backwards compatability, `if` must have lower precedence than `|` on both sides (or equivalently, for both meanings of `|`). For that reason, guard patterns nested within or-patterns must be explicitly parenthesized:
90+
91+
```rust
92+
// This is not an or-pattern of guards:
93+
a if b | c if d
94+
<=> (a if (b | c)) if d
95+
96+
// Instead, write
97+
(a if b) | (c if d)
9098
```
9199

92-
For that reason, guard patterns nested within or-patterns must be explicitly parenthesized.
93-
Otherwise, the `|` will be parsed as a bitwise OR to maintain backwards compatability with match arm guards.
100+
## In Assignment-Like Contexts
94101

95-
There's a similar ambiguity between `=` used as the assignment operator within the guard
96-
and used outside to indicate assignment to the pattern (e.g. in `if`-`let`, `while let`, etc.).
102+
There's an ambiguity between `=` used as the assignment operator within the guard
103+
and used outside to indicate assignment to the pattern (e.g. in `if let`)
97104
Therefore guard patterns appearing at the top level in those places must also be parenthesized:
98105

99106
```rust
100-
while let x if guard(x) = foo() {} // not allowed
101-
while let (x if guard(x)) = foo() {} // allowed
107+
// Not allowed:
108+
let x if guard(x) = foo() {}
109+
if let x if guard(x) = foo() {}
110+
while let x if guard(x) = foo() {}
111+
112+
// allowed
113+
let (x if guard(x)) = foo() {} // Note that this would still error after parsing, since guard patterns are always refutable.
114+
if let (x if guard(x)) = foo() {}
115+
while let (x if guard(x)) = foo() {}
102116
```
103117

104118
Therefore the syntax for patterns becomes
@@ -111,7 +125,7 @@ Therefore the syntax for patterns becomes
111125
> _PatternNoTopGuard_ :\
112126
> &nbsp;&nbsp; &nbsp;&nbsp; `|`<sup>?</sup> _PatternNoTopAlt_ ( `|` _PatternNoTopAlt_ )<sup>\*</sup>
113127
114-
With `if let`, `while let`, and `for` expressions now using `PatternNoTopGuard`. `let` statements can continue to use `PatternNoTopAlt`.
128+
With `if let` and `while let` expressions now using `PatternNoTopGuard`. `let` statements and function parameters can continue to use `PatternNoTopAlt`.
115129

116130
## Bindings Available to Guards
117131

0 commit comments

Comments
 (0)