-
Notifications
You must be signed in to change notification settings - Fork 13k
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
MBE (macro_rules!) pattern-matching is unnecessarily O(n) even in simple cases. #68836
Comments
In the |
I imagine the "proper" way to do this today is a proc macro, right? Where you can appropriately use a HashMap, for example, for such a macro? I'm not sure we should dedicate time to fixing this if proc macros do indeed make things much better here (and are 1-1 compatible, hygiene wise, in the relative short term with MBE hygiene stabilization). |
cc @mark-i-m |
I'm personally not in favor of complicating the mbe implementation more. It's already quite hard to understand and reason about, and it has a lot of weird corner cases (i.e. allowing surprising behavior) despite our best efforts. If more time is spent on the mbe implementation, I would say it should be to redo the algorithm from scratch and replace it in the next edition or as after a crater run. |
To be more concrete, I think we should focus on |
I think that we can get a lot of mileage out of having a "compilation step" that both checks the definition and transforms it into something more amenable to simple and fast pattern-matching. I agree that we should probably not bolt on such optimizations to the existing implementation, and instead try to include them as part of a simpler implementation. |
@eddyb I agree with you in principle, but I guess I can't see how it can be done. The hard part is that the current implementation (and thus the stable interface) allows all sorts of crazy things that makes it impossible to check almost anything very conclusively, as we discovered in #61053. For example, it is impossible to determine whether a macro_rules defines a new macro_rules without seeing the use site. This in turn means that we cannot have a complete check for whether all metavariables are well-defined at the definition site (since they may be defined at the call-site by a macro generated there). In my opinion, we need to first RFC major restrictions on MBEs to make these checks possible to implement at all. In particular:
There are a few other improvements that were identified in #61053 too, which would be good to implement... Also, cc @ia0 who was involved in implementing those lints... |
How can you possibly enforce this when macros can take and interpolate arbitrary token streams?! I thought you were worried about things like ambiguities or compatibility hazards in the patterns of a macro, not anything to do with what the macro expands to. With what I've seen in the wild, I don't see how what you're describing is realistically possible, even with an edition (and an edition would still require supporting the older behavior). |
Admittedly, that one seems like a bit of a stretch, but It seems plausible if we say that you can only use a
Most of my concerns are about the patterns, but the fact that a macro can expand to arbitrary things restricts what we can assume about it when checking usage of metavariables. |
Yeah,
Why do we now care about usage? This is the first time I hear about this, compared to, say, compatibility hazards in terms of an earlier arm succeeding in newer versions. |
@eddyb I should maybe clarify that when I say "valid rust", I mean syntactically, not semantically (e.g. there may still be type errors etc). Perhaps you can elaborate what you mean? How can this produce arbitrary rust syntax if
I feel that current macro error messages are... not great. And I think this is largely due to the fact that it is very hard to check the body of a macro at definition time. Rather, we have to wait for it to be instantiated so we can see what the whole thing expands too. |
I did mean
This is getting pretty offtopic but I strongly disagree. Recent research into resugaring might also be relevant. |
I think this can be closed. I did a lot of work earlier in the year speeding up declarative macro expansion and this pattern (many rules and no metavariables) barely came up at all, because it's so rare. Other than |
Before #102895, rustc used to use this pattern as well for the query system, but now it doesn't anymore. |
There are some crates which do something like this (e.g.
string_cache_codegen
):(@nnethercote came across this when profiling
html5ever
's compilation)Also, prefixing patterns with
@foo
to create "internal rules" is common.But the current implementation (AFAICT) has to check each of the patterns in turn.
Instead, we could build something like a decision tree ahead of time, from the constant (i.e.
$
-less) prefix of all arms, using maps for operators/idents/literals, to make the pattern-matching of the prefix amortize to being linear in the number of input tokens.We could keep it simple by limiting the constant prefix to leaf tokens (no
(...)
,[...]
or{...}
).For the example above, we'd pre-compute something like this:
Whereas for something using
@foo
rules it could be:(where
DecisionTree::Done
indicates the arms to continue with)cc @rust-lang/compiler (this might need a design meeting?)
The text was updated successfully, but these errors were encountered: