seem to behave differently. The former would fail to compile with expected identifier, found keyword else while the latter would compile just fine.
I'm working on this PR: feat(WIP):attributes on select! branches by drHuangMHT · Pull Request #5398 · tokio-rs/tokio · GitHub and it involves macro that uses " Incremental TT munchers". tests would fail with expected identifier, found keyword else which is counter-intuitive because there is a branch that would catch else as keyword.
I'm using stable-x86_64-unknown-linux-gnu rustc 1.67.0 (fc594f156 2023-01-24) and the online playground poses the same problem.
The macro transcriber doesn't have any lookahead and explicitly tests each arm in order, so exceptions/special cases have to be listed before the general case.
Here, it appears that else is being matched by a $pat matcher which then immediately errors. I'm not familiar enough with Rust's formal grammar to be sure, but if else is actually forbidden as the first token in a pattern, then this seems like a bug in the definition of $pat— It should instead not match and allow the next branch to be tried.
Here's a reduced example of this behavior:
macro_rules! test_pattern_matcher {
($pat:pat) => ()
}
fn f() {
// OK
test_pattern_matcher!(x);
// error: no rules expected token `+`
// (would check next match arm if present)
test_pattern_matcher!(+);
// error: expected identifier, found keyword `else`
// (matched, then errored, which stops parsing)
test_pattern_matcher!(else);
}
I think treating keywords and indents the same here might have some advantages: it wouldn't be a breaking change to the macro_rules system to make certain keywords no longer be keywords. Otherwise, such a change would probably need to be accompanied with introduction of another legacy fragment specifier like pat_param for pat when patterns could no longer be terminated by “|”. Except, a bunch of them, one for each kind of fragment that previously could not start with the keyword in question, which could mean all of stmt, pat, expr, ty, and path.
You can use r#else to use keyword else(or any other keyword) as an identifier. But that is basically a literal different from "else". However, the compiler will omit the "r#" in its output, but sometimes.