-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
rustc_hir: add Expr! pattern macro and try it out in a couple places. #68320
rustc_hir: add Expr! pattern macro and try it out in a couple places. #68320
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
Interesting. This could affect some of the "chalk-ty" questions. In particular, I've been wondering about whether to use "a few general variants" or "lots of fine-grained variants". The latter are annoying most of the time but potentially a more space-efficient representation, and occasionally convenient. Pattern aliases might "sort of" side-step the problem, at the cost of being a weird pattern with worse error messages. |
☔ The latest upstream changes (presumably #67476) made this pull request unmergeable. Please resolve the merge conflicts. |
My knee-jerk reaction is "I don't like this". Fragments with |
/// * `hir::Expr! { Loop(..), hir_id: loop_id }` | ||
pub macro Expr($variant:ident $($rest:tt)*) { | ||
$crate::hir::Expr { | ||
kind: $crate::hir::ExprKind::$variant $($rest)*, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$crate
-> crate
here and one line above, macro
s are fully hygienic and don't need $crate
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to be conservative, presumably I can even write Expr
without the full module path.
Perhaps if there's a convention, and these macros are used consistently, and everyone knows what We probably need to estimate how often (Also, these macros can be generated with derives instead of being written manually for each struct.) |
I sorta feel the same as @petrochenkov and don't think I would be game to implement use of this myself. Beyond making code more cryptic, remember that macro usage like this angers rust-analyzer in general, making interactions with IDEs worse. |
We don't expand macros in patterns in rust-analyzer right now, but I think implementing it would mostly be trivial 🙂 Support for macros 2.0 is non-existent though, and completion within the macro call would be a problem. |
To be clear, that's not the usecase I'm targeting, because that sort of code is avoided, and instead we rely on nested matches in a bunch of places. However, I also understand if the people working with the relevant data structures would prefer to avoid macros, and wait until we have pattern aliases to do any ergonomic overhauls (if ever). I have unrelated projects which use indices for interning, not references, and so pattern aliases wouldn't help there, so I might try the macro approach there. Anyway, I mostly wanted to bring it up in case we overlooked this sort of thing being possible at all, not to champion it. I'll leave the PR open for maybe another week but only so more people have a chance to see it. |
/// Usage examples: | ||
/// * `hir::Expr!(Unary(_, hir::Expr!(Lit(_))))` | ||
/// * `hir::Expr! { Loop(..), hir_id: loop_id }` | ||
pub macro Expr($variant:ident $($rest:tt)*) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use pat
fragment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because then people would have to write hir::ExprKind::Foo
instead of Foo
, inside the macro arguments.
And also this allows some trickery like matching on the hir_id
(although maybe that should be done with EDIT: nevermind, @
instead of this@
needs a binding on one side, it's not a conjunction of patterns).
Discussed at T-compiler meeting. Of those present, general feeling was that no one was enthusiastic about making this change. We will leave this open for now, with the intent to close in a week or so unless a champion comes forward. |
A week has passed. |
Note to self: don't delete the branch in case someone comes across this later. |
Came across more usecases for pattern aliases today, and realized we can use macros instead!
EDIT: I just checked, and pattern macros seem to be stable in 1.0? But they wouldn't have been scoped.
(click for backstory - TL;DR: pattern-matching
Ty
instead ofTyKind
)I wanted to be able to write something like this, so that when the type doesn't match, it's printed (as opposed to just
assert!(ty.is_ref() || ty.is_ptr())
):But that would print
ty.kind
, instead ofty
, so I'd want to match onty
instead:The other example I came up with was
ty::Ref!(_, _, ty::Str!())
(for&str
).Here that idea is applied to HIR (and just
Expr
in particular), with a few patterns across the codebase replaced, to get a first impression of what can be done with it.In the first commit I've included two examples (
rustc_lint::builtin
andrustc_typeck::astconv
), which I found more interesting, while the second commit is more of a random set of replacements.The definition of
hir::Expr!
, if we elide$crate::hir::
paths, looks like this:At its most basic, this allows writing e.g.
hir::Expr!(Lit(_))
in a pattern.But the real benefit comes from making nesting straightforward, e.g.:
Also, you may have noticed the definition is technically more flexible than it needs to be.
This allows mentioning other fields as well, e.g.
hir::Expr! { Path(_), hir_id: path_hir_id }
.I'm not attached to the syntax, but I think this is a neat ability.
The most complex pattern in this PR, after rustfmt, looks like this:
This probably qualifies for a @rust-lang/compiler design meeting discussion, but this is a rabbit hole I don't want to spend much time on, maybe @Centril or others are interested in taking over?