Uh oh!
There was an error while loading. Please reload this page.
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.#68320eddyb wants to merge 2 commits into
Conversation
rust-highfive
commented
Jan 17, 2020
(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. |
bors
commented
Jan 18, 2020
☔ The latest upstream changes (presumably #67476) made this pull request unmergeable. Please resolve the merge conflicts. |
petrochenkov
commented
Jan 18, 2020
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.
$crate -> crate here and one line above, macros are fully hygienic and don't need $crate.
There was a problem hiding this comment.
I wanted to be conservative, presumably I can even write Expr without the full module path.
petrochenkov
commented
Jan 18, 2020
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.) |
Centril
commented
Jan 18, 2020
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. |
flodiebold
commented
Jan 18, 2020
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. |
eddyb
commented
Jan 18, 2020
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.
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).
pnkfelix
commented
Jan 23, 2020
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. |
petrochenkov
commented
Jan 30, 2020
A week has passed. |
eddyb
commented
Jan 31, 2020
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
Tyinstead 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 ontyinstead:The other example I came up with was
ty::Ref!(_, _, ty::Str!())(for&str).Here that idea is applied to HIR (and just
Exprin 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::builtinandrustc_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?