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

Guard Patterns #3637

Merged
merged 18 commits into from
Sep 4, 2024
Merged
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
36 changes: 36 additions & 0 deletions text/3637-guard-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,42 @@ If guards can only appear immediately within or-patterns, then either

This can also be seen as a special case of the previous argument, as pattern macros fundamentally assume that patterns can be built out of composable, local pieces.

## Deref and Const Patterns Must Be Pure, But Not Guards

It may seem odd that we explicitly require `deref!` and const patterns to use pure `Deref` and `PartialEq` implementations, respectively, but allow arbitrary side effects in guards. The ultimate reason for this is that, unlike `deref!` and const patterns, guard patterns are always refutable.
traviscross marked this conversation as resolved.
Show resolved Hide resolved

With `deref!` patterns, we can write an impure `Deref` impl which alternates between returning `true` or `false` to get UB:
```rust
match EvilBox::new(false) {
deref!(true) => {} // Here the `EvilBox` dereferences to `false`.
deref!(false) => {} // And here to `true`.
}
```

And similarly, without the requirement of `StructuralPartialEq` we could write a `PartialEq` implementation which always returns `false`:

```rust
const FALSE: EvilBool = EvilBool(false);
const TRUE: EvilBool = EvilBool(true);

match EvilBool(false) {
FALSE => {},
TRUE => {},
}
```

However, this is not a problem with guard patterns because they already need a irrefutable alternative anyway.
max-niederman marked this conversation as resolved.
Show resolved Hide resolved
For example, we could rewrite the const pattern example with guard patterns as follows:

```rust
match EvilBool(false) {
x if x == FALSE => {},
x if x == TRUE => {},
}
```

But this will always be a compilation error because the `match` statement is no longer assumed to be exhaustive.

# Prior art
[prior-art]: #prior-art

Expand Down