-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Macro fragment specifiers edition policy #3531
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
Merged
traviscross
merged 7 commits into
rust-lang:master
from
traviscross:TC/macro-fragment-policy
Dec 6, 2023
Merged
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ee6e943
Add RFC for macro fragment specifiers edition policy
traviscross a115ba8
Specify how `cargo fix` will act
traviscross 6380691
Specify when specifiers are added and to what editions
traviscross 3b4c9e6
Add alternative of new edition behavior in all editions
traviscross 48cde3d
Add caveat on adding new specifier to all editions
traviscross 8e4cefe
Switch from `expr2021` to `expr_2021`
traviscross 8aefa12
Add exception for when we can update the specifier
traviscross File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Macro matcher fragment specifiers edition policy | ||
|
||
- Start Date: 2023-11-15 | ||
- RFC PR: [rust-lang/rfcs#3531](https://github.com/rust-lang/rfcs/pull/3531) | ||
|
||
# Summary | ||
|
||
This RFC sets out the policy for how the behavior of macro matcher fragment specifiers is updated over an edition when those specifiers fall out of sync with the underlying grammar of Rust. | ||
|
||
# Background and motivation | ||
|
||
Rust has a syntactic abstraction feature called ["macros by example"][] or `macro_rules`. This feature allows for writing *macros* that transform source code in a principled way. | ||
|
||
Each macro is composed of one or more *rules*. Each of these rules has a *matcher*. The matcher defines what pattern of Rust syntax will be matched by the rule. | ||
|
||
Within a matcher, different parts of the input Rust syntax can be bound to metavariables using *[fragment specifiers][]*. These fragment specifiers define what Rust syntax will be matched and bound to each metavariable. For example, the `item` fragment specifier matches an [item][], `block` matches a [block expression][], `expr` matches an [expression][], and so on. | ||
|
||
As we add new features to Rust, sometimes we change its syntax. This means that, even within an edition, the definition of what exactly constitutes an [expression][], e.g., can change. However, to avoid breaking macros in existing code covered by our stability guarantee, we do not update within an edition what code is matched by the relevant fragment specifier (e.g., `expr`). This *skew* or divergence between the language and the fragment specifiers creates problems over time, including that macros become unable to match newer Rust syntax without dropping down to lower-level specifiers such as `tt`. | ||
|
||
Periodically, we need a way to bring the language and the fragment specifiers back into sync. This RFC defines a policy for how we do that. | ||
|
||
["macros by example"]: https://doc.rust-lang.org/reference/macros-by-example.html | ||
[block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html | ||
[expression]: https://doc.rust-lang.org/reference/expressions.html | ||
[fragment specifiers]: https://doc.rust-lang.org/reference/macros-by-example.html#metavariables | ||
[item]: https://doc.rust-lang.org/reference/items.html | ||
|
||
# Policy | ||
|
||
This section is normative. | ||
|
||
When we have changed the syntax of Rust such that the syntax matched by a fragment specifier no longer exactly aligns with the actual syntax for that production in the Rust grammar, then for the next edition of Rust, we will: | ||
|
||
- Add a new fragment specifier that preserves the behavior of the fragment specifier in the last edition. If there is some semantically meaningful name that makes sense to use for this new fragment specifier, we'll use that. Otherwise, we'll use the existing name with the identifier of the last edition added as a suffix. | ||
- Change the behavior of the fragment specifier to match the underlying grammar as of the release of Rust corresponding to first release of the new edition. | ||
|
||
For example, suppose that the behavior of the `expr` fragment specifier fell out of sync with the grammar for a Rust [expression][] during Rust 2021 and that Rust 2024 is the next edition. Then in Rust 2024, we would add a new fragment specifier named `expr2021` (assuming no better semantically meaningful name could be found) that would preserve the behavior `expr` had in Rust 2021, and we would change the behavior of `expr` to match the underlying grammar. | ||
|
||
# Alternatives | ||
|
||
## Keep the old, add specifiers for the new | ||
|
||
Changing the behavior of existing fragment specifiers, even over an edition, has an obvious cost: we may change the meaning of existing macros and consequently change the code that they generate. | ||
|
||
One way to mitigate this would be for `cargo fix` to replace all instances of a changed fragment specifier with the new fragment specifier added for backward compatibility. But that has some cost in terms of code churn. | ||
traviscross marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Another alternative would be to *never* change the meaning of existing fragment specifiers. Instead, when changing the grammar of Rust, we would add *new* fragment specifiers that would correspond with this new grammar. We would not have to wait for new editions to add these. We could add, e.g., `expr2023_11`, `expr2023_12`, etc. each time that we change the grammar. | ||
|
||
This would be burdensome in other ways, so we've decided not to do this. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.