Skip to content

Commit 0a0ad79

Browse files
authored
Merge pull request #252 from rylev/or-patterns-update
Add migration details to or-patterns guide
2 parents a604a15 + 2a44ae0 commit 0a0ad79

File tree

1 file changed

+52
-12
lines changed

1 file changed

+52
-12
lines changed

src/rust-2021/or-patterns-macro-rules.md

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
## Summary
44

5-
- `$_:pat` in `macro_rules` now matches `|` too: e.g. `A | B`.
6-
- `$_:pat_param` behaves like `$_:pat` did before; it does not match (top level) `|`.
7-
- `$_:pat_param` is available in all editions.
5+
- How patterns work in `macro_rules` macros changes slightly:
6+
- `$_:pat` in `macro_rules` now matches usage of `|` too: e.g. `A | B`.
7+
- The new `$_:pat_param` behaves like `$_:pat` did before; it does not match (top level) `|`.
8+
- `$_:pat_param` is available in all editions.
89

910
## Details
1011

@@ -15,18 +16,57 @@ Since this was simply not allowed before, this is not a breaking change.
1516

1617
However, this change also affects [`macro_rules` macros](https://doc.rust-lang.org/stable/reference/macros-by-example.html).
1718
Such macros can accept patterns using the `:pat` fragment specifier.
18-
Currently, `:pat` does *not* match `|`, since before Rust 1.53,
19+
Currently, `:pat` does *not* match top level `|`, since before Rust 1.53,
1920
not all patterns (at all nested levels) could contain a `|`.
2021
Macros that accept patterns like `A | B`,
2122
such as [`matches!()`](https://doc.rust-lang.org/1.51.0/std/macro.matches.html)
22-
use something like `$($_:pat)|+`.
23-
Because we don't want to break any existing macros,
24-
we did *not* change the meaning of `:pat` in Rust 1.53.0 to include `|`.
23+
use something like `$($_:pat)|+`.
2524

26-
Instead, we will make that change as part of Rust 2021.
25+
Because this would potentially break existing macros, the meaning of `:pat` did
26+
not change in Rust 1.53.0 to include `|`. Instead, that change happens in Rust 2021.
2727
In the new edition, the `:pat` fragment specifier *will* match `A | B`.
2828

29-
Since there are times that one still wishes to match a single pattern
30-
variant without `|`, the fragment specified `:pat_param` has been added
31-
to retain the older behavior.
32-
The name refers to its main use case: a pattern in a closure parameter.
29+
`$_:pat` fragments in Rust 2021 cannot be followed by an explicit `|`. Since there are times
30+
that one still wishes to match pattern fragments followed by a `|`, the fragment specified `:pat_param`
31+
has been added to retain the older behavior.
32+
33+
It's important to remember that editions are _per crate_, so the only relevant edition is the edition
34+
of the crate where the macro is defined. The edition of the crate where the macro is used does not
35+
change how the macro works.
36+
37+
## Migration to Rust 2021
38+
39+
A lint, `rust_2021_incompatible_or_patterns`, gets triggered whenever there is a use `$:_pat` which
40+
will change meaning in Rust 2021.
41+
42+
You can automatically migrate your code to be Rust 2021 Edition compatible or ensure it is already compatible by
43+
running:
44+
45+
```sh
46+
cargo fix --edition
47+
```
48+
49+
If you have a macro which relies on `$_:pat` not matching the top level use of `|` in patterns,
50+
you'll need to change each occurrence of `$_:pat` to `$_:pat_param`.
51+
52+
For example:
53+
54+
```rust
55+
macro_rules! my_macro {
56+
($x:pat | $y:pat) => {
57+
// TODO: implementation
58+
}
59+
}
60+
61+
// This macro works in Rust 2018 since `$x:pat` does not match against `|`:
62+
my_macro!(1 | 2);
63+
64+
// In Rust 2021 however, the `$_:pat` fragment matches `|` and is not allowed
65+
// to be followed by a `|`. To make sure this macro still works in Rust 2021
66+
// change the macro to the following:
67+
macro_rules! my_macro {
68+
($x:pat_param | $y:pat) => { // <- this line is different
69+
// TODO: implementation
70+
}
71+
}
72+
```

0 commit comments

Comments
 (0)