Polish some macro parsing code#158577
Conversation
|
Thanks for the pull request, and welcome! The Rust Project is excited to review your changes, and you should hear from @nnethercote (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
This comment has been minimized.
This comment has been minimized.
a0f4444 to
e9fd0f3
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Thanks for the PR and welcome to rust-lang/rust!
Five of these eight commits look good to me, and for three of them I have concerns.
- Replace Cow with an explicit fast-path is extra complexity and I don't think it's a net improvement. More details below.
- Move ambiguity handling into Tracker is doing multiple things at once which makes it hard to follow. In particular, I'm not sure which parts are pure refactoring vs. new functionality. (More below.) Are you able to split these into multiple commits? It's fine to rewrite git history and then re-push.
- fixup: TODO -> FIXME should be folded into the first commit, but if that one is removed then this one won't be necessary.
| parser.approx_token_stream_pos(), | ||
| "no rules expected this token in macro call", | ||
| )); | ||
| } |
There was a problem hiding this comment.
Where did this code come from? It looks like it's a special extracted from a mixture of parse_tt and parse_tt_inner, I think? It's non-trivial, non-obvious duplication of code from other paths, which I don't like. I don't think the removal of Cow is much of a win (Cow makes the "this might get cloned" behaviour more explicit) and even if it is a win, the extra complexity here outweighs it.
There was a problem hiding this comment.
That's fair. This change originally fell out after I had made the BFS->DFS change, which merged the logic between parse_tt and parse_tt_inner and so made the duplication more obvious. I'll remove this commit from the PR and keep it for later, applying it after the BFS->DFS change to see whether it makes more sense in that context.
| // Distinguish meta-variable matchers from others. | ||
| let (metavar_locs, fixed_locs) = locs | ||
| .into_iter() | ||
| .partition::<Vec<_>, _>(|loc| matches!(loc, MatcherLoc::MetaVarDecl { .. })); |
There was a problem hiding this comment.
This partition is new and the commit message didn't mention it. What's happening here? Does this change the error message?
There was a problem hiding this comment.
This change is inspired by the BFS->DFS switch I will make later, where I lose the separation between bb_mps and next_mps/cur_mps. But I don't think it's necessary right now, and clearly it's introducing some new complexity.
I think I will change this method's signature to take bb_mps and next_mps as separate arguments; I can change the parameters again in the BFS->DFS PR to fit its needs. I still think this commit (moving ambiguity handling to the tracker) is worthwhile so I'll keep it in.
|
@rustbot author |
|
Reminder, once the PR becomes ready for a review, use |
There was a problem hiding this comment.
Thanks for the PR and welcome to rust-lang/rust!
❤️
Five of these eight commits look good to me, and for three of them I have concerns.
- Replace Cow with an explicit fast-path is extra complexity and I don't think it's a net improvement. More details below.
I'll take it out of this PR and possibly re-introduce it in the BFS->DFS PR, I think it'll feel like a better fit at that point.
- Move ambiguity handling into Tracker is doing multiple things at once which makes it hard to follow. In particular, I'm not sure which parts are pure refactoring vs. new functionality. (More below.) Are you able to split these into multiple commits? It's fine to rewrite git history and then re-push.
Yep, that commit could use some more splitting, I'm on it :)
- fixup: TODO -> FIXME should be folded into the first commit, but if that one is removed then this one won't be necessary.
I was going to fold that into the responsible commit before merging for sure :) But as you said, it'll probably disappear from this PR anyways.
| parser.approx_token_stream_pos(), | ||
| "no rules expected this token in macro call", | ||
| )); | ||
| } |
There was a problem hiding this comment.
That's fair. This change originally fell out after I had made the BFS->DFS change, which merged the logic between parse_tt and parse_tt_inner and so made the duplication more obvious. I'll remove this commit from the PR and keep it for later, applying it after the BFS->DFS change to see whether it makes more sense in that context.
| // Distinguish meta-variable matchers from others. | ||
| let (metavar_locs, fixed_locs) = locs | ||
| .into_iter() | ||
| .partition::<Vec<_>, _>(|loc| matches!(loc, MatcherLoc::MetaVarDecl { .. })); |
There was a problem hiding this comment.
This change is inspired by the BFS->DFS switch I will make later, where I lose the separation between bb_mps and next_mps/cur_mps. But I don't think it's necessary right now, and clearly it's introducing some new complexity.
I think I will change this method's signature to take bb_mps and next_mps as separate arguments; I can change the parameters again in the BFS->DFS PR to fit its needs. I still think this commit (moving ambiguity handling to the tracker) is worthwhile so I'll keep it in.
While familiarizing myself with this code, it took me a while to figure out the meaning and need for this boolean. Making it an explicit enum seems to be convention here, and it makes it easy to understand its purpose. `tests/ui/macros` pass.
Duplicate meta-variable bindings are already checked for when building a macro definition, in `macro_check.rs`. If duplicates are detected, the macro definition is replaced with a dummy, so duplicate bindings are impossible at macro instantiation time. Instead of treating them like an error, report a `bug!` instead. This simplifies things semantically: now a `NamedParseResult::Error` can only be caused by an ambiguity error. This allows it to be specialized a bit. `tests/ui/macros` pass.
`tests/ui/macros` pass.
7b5c3be to
d4adbf8
Compare
|
@rustbot ready |
This comment has been minimized.
This comment has been minimized.
| /// and we want to prioritize earlier failures over later ones, so we use [`WhichMatcher`]. | ||
| /// | ||
| /// The second element is the approximate parser position. | ||
| position_in_tokenstream: (WhichMatcher, u32), |
There was a problem hiding this comment.
Possible follow-up: split this tuple into separate fields, because the tuple doesn't really add anything?
|
Move ambiguity handling into Tracker hasn't been split up? In the meantime, let's do a perf run, just in case it has an effect: @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Polish some macro parsing code
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (f4b2f2d): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)This perf run didn't have relevant results for this metric. CyclesResults (secondary -2.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 485.944s -> 483.648s (-0.47%) |
|
The queue is actually not that bad right now, relatively speaking, I'd rather give it one more try on its own as perf-sensitive PRs in rollups are still annoying for perf triage |
|
@bors p=6 |
This comment has been minimized.
This comment has been minimized.
Polish some macro parsing code I'm working on some optimizations to `macro_parser.rs` and the surrounding code (specifically, changing the current BFS approach into a DFS), and these changes fell out during that effort. I think they make the code more accessible in addition to laying some foundations for my future work (in particular, the handling of ambiguities). This is my first proper entrance into rustc code, please let me know if I'm holding something wrong :) The commits are organized and individually reviewable. r? @nnethercote
|
#158847 suffered exactly the same failure as the previous build here did ... is there an actual failure on |
|
💔 Test for 59236e4 failed: CI. Failed job:
|
|
@bors retry |
|
A job failed! Check out the build log: (web) (plain enhanced) (plain) Click to see the possible cause of the failure (guessed by this bot) |
This comment has been minimized.
This comment has been minimized.
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing c4af710 (parent) -> b960fcf (this PR) Test differencesShow 2 test diffs2 doctest diffs were found. These are ignored, as they are noisy. Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard b960fcf2ff0f04967b30b947be8fc155fb067901 --output-dir test-dashboardAnd then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
|
Finished benchmarking commit (b960fcf): comparison URL. Overall result: ✅ improvements - no action needed@rustbot label: -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary 5.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary -3.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 490.62s -> 489.183s (-0.29%) |
Preparatory changes for macro parsing BFS->DFS This PR contains some miscellaneous commits I accumulated while working on the BFS->DFS change. Their goal is to simplify the code and clarifying existing behavior. It is a conceptual follow-up to #158577. High-level overview: - Adds context about the current match arm to `Tracker` through the new `Tracker::prepare()`, so that the `WhichMatcher` parameter is available implicitly. In a later PR, this will be used to reference `MatcherLoc`s by index. - Reformulates matching failures to work more like ambiguity errors wrt. `Tracker`; `Tracker::build_failure()` (which would build a failure consumed by `Tracker::after_arm()`) becomes `Tracker::failure()` which eagerly processes the error. This removes the need for `ParseResult::Failure` to store any data at all. This relies on the match arm context provided by `Tracker::prepare()`. - There is a subtle edge case involving `token::Eof` and non-terminal parsing; `Parser::nonterminal_may_begin_with()` would sometimes return `true` for `token::Eof`, even though the non-terminal parse would never be attempted. `TtParser` did not check `bb_mps` when handling `token::Eof`, so non-terminal parses at EOF were being silently dropped. I changed `Parser::nonterminal_may_begin_with()` to always return `false` for `token::Eof`, making this behavior much more visible. I added a test case to make sure meta-variables return the same error uniformly when parsed against EOF. Contains #158894, which should be merged soon (after which I'll rebase onto `main`). Best reviewed commit-by-commit. r? @nnethercote
Preparatory changes for macro parsing BFS->DFS This PR contains some miscellaneous commits I accumulated while working on the BFS->DFS change. Their goal is to simplify the code and clarifying existing behavior. It is a conceptual follow-up to #158577. High-level overview: - Adds context about the current match arm to `Tracker` through the new `Tracker::prepare()`, so that the `WhichMatcher` parameter is available implicitly. In a later PR, this will be used to reference `MatcherLoc`s by index. - Reformulates matching failures to work more like ambiguity errors wrt. `Tracker`; `Tracker::build_failure()` (which would build a failure consumed by `Tracker::after_arm()`) becomes `Tracker::failure()` which eagerly processes the error. This removes the need for `ParseResult::Failure` to store any data at all. This relies on the match arm context provided by `Tracker::prepare()`. - There is a subtle edge case involving `token::Eof` and non-terminal parsing; `Parser::nonterminal_may_begin_with()` would sometimes return `true` for `token::Eof`, even though the non-terminal parse would never be attempted. `TtParser` did not check `bb_mps` when handling `token::Eof`, so non-terminal parses at EOF were being silently dropped. I changed `Parser::nonterminal_may_begin_with()` to always return `false` for `token::Eof`, making this behavior much more visible. I added a test case to make sure meta-variables return the same error uniformly when parsed against EOF. Contains #158894, which should be merged soon (after which I'll rebase onto `main`). Best reviewed commit-by-commit. r? @nnethercote
Preparatory changes for macro parsing BFS->DFS This PR contains some miscellaneous commits I accumulated while working on the BFS->DFS change. Their goal is to simplify the code and clarifying existing behavior. It is a conceptual follow-up to #158577. High-level overview: - Adds context about the current match arm to `Tracker` through the new `Tracker::prepare()`, so that the `WhichMatcher` parameter is available implicitly. In a later PR, this will be used to reference `MatcherLoc`s by index. - Reformulates matching failures to work more like ambiguity errors wrt. `Tracker`; `Tracker::build_failure()` (which would build a failure consumed by `Tracker::after_arm()`) becomes `Tracker::failure()` which eagerly processes the error. This removes the need for `ParseResult::Failure` to store any data at all. This relies on the match arm context provided by `Tracker::prepare()`. - There is a subtle edge case involving `token::Eof` and non-terminal parsing; `Parser::nonterminal_may_begin_with()` would sometimes return `true` for `token::Eof`, even though the non-terminal parse would never be attempted. `TtParser` did not check `bb_mps` when handling `token::Eof`, so non-terminal parses at EOF were being silently dropped. I changed `Parser::nonterminal_may_begin_with()` to always return `false` for `token::Eof`, making this behavior much more visible. I added a test case to make sure meta-variables return the same error uniformly when parsed against EOF. Contains #158894, which should be merged soon (after which I'll rebase onto `main`). Best reviewed commit-by-commit. r? @nnethercote
Preparatory changes for macro parsing BFS->DFS This PR contains some miscellaneous commits I accumulated while working on the BFS->DFS change. Their goal is to simplify the code and clarifying existing behavior. It is a conceptual follow-up to rust-lang/rust#158577. High-level overview: - Adds context about the current match arm to `Tracker` through the new `Tracker::prepare()`, so that the `WhichMatcher` parameter is available implicitly. In a later PR, this will be used to reference `MatcherLoc`s by index. - Reformulates matching failures to work more like ambiguity errors wrt. `Tracker`; `Tracker::build_failure()` (which would build a failure consumed by `Tracker::after_arm()`) becomes `Tracker::failure()` which eagerly processes the error. This removes the need for `ParseResult::Failure` to store any data at all. This relies on the match arm context provided by `Tracker::prepare()`. - There is a subtle edge case involving `token::Eof` and non-terminal parsing; `Parser::nonterminal_may_begin_with()` would sometimes return `true` for `token::Eof`, even though the non-terminal parse would never be attempted. `TtParser` did not check `bb_mps` when handling `token::Eof`, so non-terminal parses at EOF were being silently dropped. I changed `Parser::nonterminal_may_begin_with()` to always return `false` for `token::Eof`, making this behavior much more visible. I added a test case to make sure meta-variables return the same error uniformly when parsed against EOF. Contains rust-lang/rust#158894, which should be merged soon (after which I'll rebase onto `main`). Best reviewed commit-by-commit. r? @nnethercote
View all comments
I'm working on some optimizations to
macro_parser.rsand the surrounding code (specifically, changing the current BFS approach into a DFS), and these changes fell out during that effort. I think they make the code more accessible in addition to laying some foundations for my future work (in particular, the handling of ambiguities).This is my first proper entrance into rustc code, please let me know if I'm holding something wrong :)
The commits are organized and individually reviewable.
r? @nnethercote