Skip to content

Commit a27606c

Browse files
committed
Accept T or delimited versus NT or seq cases where the rest of the matcher only contain simple tokens.
Those were rejected before when the NT or seq can match several token trees because we did not know where to continue the analysis. But if the rest of the first matcher does not contain any NT matcher, we do not need to continue the analysis.
1 parent 035b698 commit a27606c

File tree

1 file changed

+44
-19
lines changed

1 file changed

+44
-19
lines changed

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
594594
// matches A will never match B or vice-versa
595595
// * we find a case that is too complex to handle and reject it
596596
// * we reach the end of the macro
597-
for (ta, tb) in ma.iter().zip(mb.iter()) {
597+
for ((idx_a, ta), tb) in ma.iter().enumerate().zip(mb.iter()) {
598598
if match_same_input(ta, tb) {
599599
continue;
600600
}
@@ -608,18 +608,25 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
608608
// not tt, ident, or block (that is, either A or B could match several
609609
// token trees), we cannot know where we should continue the analysis.
610610
match (ta, tb) {
611-
(&TokenTree::Sequence(_, _), _) |
612-
(_, &TokenTree::Sequence(_, _)) => return false,
613-
614611
(&TokenTree::Token(_, MatchNt(_, nta)),
615612
&TokenTree::Token(_, MatchNt(_, ntb))) =>
616613
if !(nt_is_single_tt(nta) && nt_is_single_tt(ntb)) {
617614
return false
618615
},
619616

620-
(&TokenTree::Token(_, MatchNt(_, nt)), _) |
621-
(_ ,&TokenTree::Token(_, MatchNt(_, nt))) =>
622-
if !nt_is_single_tt(nt) { return false },
617+
(&TokenTree::Token(_, MatchNt(_, nt)), _) if !nt_is_single_tt(nt) =>
618+
return false,
619+
620+
// super specific corner case: if one arm is always one token,
621+
// followed by the end of the macro invocation, then we can accept
622+
// it.
623+
624+
(&TokenTree::Sequence(_, _), _) |
625+
(_, &TokenTree::Sequence(_, _)) =>
626+
return only_simple_tokens(&ma[idx_a..]) && !need_disambiguation,
627+
628+
(_ ,&TokenTree::Token(_, MatchNt(_, nt))) if !nt_is_single_tt(nt) =>
629+
return only_simple_tokens(&ma[idx_a..]) && !need_disambiguation,
623630

624631
_ => ()
625632
}
@@ -662,18 +669,26 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
662669
cx.bug("unexpeceted NT vs. Token")
663670
},
664671

665-
(&TokenTree::Token(_, MatchNt(_, nt)), &TokenTree::Delimited(_, ref delim)) |
666-
(&TokenTree::Delimited(_, ref delim), &TokenTree::Token(_, MatchNt(_, nt))) =>
667-
if nt.name.as_str() == "block"
668-
&& delim.delim == token::DelimToken::Brace {
669-
// we cannot say much here. we cannot look inside. we
670-
// can just hope we will find an obvious disambiguation later
671-
need_disambiguation = true;
672-
continue
673-
} else {
674-
// again, the other possibilites do not share any FIRST token
675-
cx.bug("unexpeceted NT vs. Delim")
676-
},
672+
(&TokenTree::Token(_, MatchNt(_, nt)),
673+
&TokenTree::Delimited(_, ref delim)) => {
674+
// should be the only possibility.
675+
assert!(nt.name.as_str() == "block" &&
676+
delim.delim == token::DelimToken::Brace);
677+
// we cannot say much here. we cannot look inside. we
678+
// can just hope we will find an obvious disambiguation later
679+
need_disambiguation = true;
680+
continue
681+
}
682+
683+
(&TokenTree::Delimited(_, ref delim),
684+
&TokenTree::Token(_, MatchNt(_, nt))) => {
685+
assert!(nt.name.as_str() == "block" &&
686+
delim.delim == token::DelimToken::Brace);
687+
// as with several-TTs NTs, if the above is only
688+
// made of simple tokens this is ok...
689+
need_disambiguation |= !only_simple_tokens(&delim.tts);
690+
continue
691+
}
677692

678693
(&TokenTree::Delimited(..), &TokenTree::Delimited(..)) => {
679694
// they have the same delim. as above.
@@ -707,6 +722,16 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
707722
}
708723
}
709724

725+
// checks that a matcher does not contain any NT except ident
726+
fn only_simple_tokens(m: &[TokenTree]) -> bool {
727+
m.iter().all(|tt| match *tt {
728+
TokenTree::Token(_, MatchNt(_, nt)) => nt.name.as_str() == "ident",
729+
TokenTree::Token(..) => true,
730+
TokenTree::Delimited(_, ref delim) => only_simple_tokens(&delim.tts),
731+
TokenTree::Sequence(_, ref seq) => only_simple_tokens(&seq.tts)
732+
})
733+
}
734+
710735
fn nt_is_single_tt(nt: ast::Ident) -> bool {
711736
match &nt.name.as_str() as &str {
712737
"block" | "ident" | "tt" => true,

0 commit comments

Comments
 (0)