@@ -117,12 +117,15 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
117
117
( $self: expr, $allow_qpath_recovery: expr) => {
118
118
if $allow_qpath_recovery
119
119
&& $self. may_recover( )
120
- && $self . look_ahead ( 1 , |t| t == & token:: PathSep )
121
- && let token:: Interpolated ( nt ) = & $self . token . kind
122
- && let token:: NtTy ( ty ) = & * * nt
120
+ && let Some ( mv_kind ) = $self . token. is_metavar_seq ( )
121
+ && let token:: MetaVarKind :: Ty { .. } = mv_kind
122
+ && $self . check_noexpect_past_close_delim ( & token:: PathSep )
123
123
{
124
- let ty = ty. clone( ) ;
125
- $self. bump( ) ;
124
+ // Reparse the type, then move to recovery.
125
+ let ty = $self
126
+ . eat_metavar_seq( mv_kind, |this| this. parse_ty_no_question_mark_recover( ) )
127
+ . expect( "metavar seq ty" ) ;
128
+
126
129
return $self. maybe_recover_from_bad_qpath_stage_2( $self. prev_token. span, ty) ;
127
130
}
128
131
} ;
@@ -614,6 +617,24 @@ impl<'a> Parser<'a> {
614
617
self . token == * tok
615
618
}
616
619
620
+ // Check the first token after the delimiter that closes the current
621
+ // delimited sequence. (Panics if used in the outermost token stream, which
622
+ // has no delimiters.) It uses a clone of the relevant tree cursor to skip
623
+ // past the entire `TokenTree::Delimited` in a single step, avoiding the
624
+ // need for unbounded token lookahead.
625
+ //
626
+ // Primarily used when `self.token` matches
627
+ // `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
628
+ // metavar expansion.
629
+ fn check_noexpect_past_close_delim ( & self , tok : & TokenKind ) -> bool {
630
+ let mut tree_cursor = self . token_cursor . stack . last ( ) . unwrap ( ) . clone ( ) ;
631
+ tree_cursor. bump ( ) ;
632
+ matches ! (
633
+ tree_cursor. curr( ) ,
634
+ Some ( TokenTree :: Token ( token:: Token { kind, .. } , _) ) if kind == tok
635
+ )
636
+ }
637
+
617
638
/// Consumes a token 'tok' if it exists. Returns whether the given token was present.
618
639
///
619
640
/// the main purpose of this function is to reduce the cluttering of the suggestions list
@@ -721,6 +742,43 @@ impl<'a> Parser<'a> {
721
742
if !self . eat_keyword ( exp) { self . unexpected ( ) } else { Ok ( ( ) ) }
722
743
}
723
744
745
+ /// Consume a sequence produced by a metavar expansion, if present.
746
+ fn eat_metavar_seq < T > (
747
+ & mut self ,
748
+ mv_kind : MetaVarKind ,
749
+ f : impl FnMut ( & mut Parser < ' a > ) -> PResult < ' a , T > ,
750
+ ) -> Option < T > {
751
+ self . eat_metavar_seq_with_matcher ( |mvk| mvk == mv_kind, f)
752
+ }
753
+
754
+ /// A slightly more general form of `eat_metavar_seq`, for use with the
755
+ /// `MetaVarKind` variants that have parameters, where an exact match isn't
756
+ /// desired.
757
+ fn eat_metavar_seq_with_matcher < T > (
758
+ & mut self ,
759
+ match_mv_kind : impl Fn ( MetaVarKind ) -> bool ,
760
+ mut f : impl FnMut ( & mut Parser < ' a > ) -> PResult < ' a , T > ,
761
+ ) -> Option < T > {
762
+ if let token:: OpenDelim ( delim) = self . token . kind
763
+ && let Delimiter :: Invisible ( InvisibleOrigin :: MetaVar ( mv_kind) ) = delim
764
+ && match_mv_kind ( mv_kind)
765
+ {
766
+ self . bump ( ) ;
767
+ let res = f ( self ) . expect ( "failed to reparse {mv_kind:?}" ) ;
768
+ if let token:: CloseDelim ( delim) = self . token . kind
769
+ && let Delimiter :: Invisible ( InvisibleOrigin :: MetaVar ( mv_kind) ) = delim
770
+ && match_mv_kind ( mv_kind)
771
+ {
772
+ self . bump ( ) ;
773
+ Some ( res)
774
+ } else {
775
+ panic ! ( "no close delim when reparsing {mv_kind:?}" ) ;
776
+ }
777
+ } else {
778
+ None
779
+ }
780
+ }
781
+
724
782
/// Is the given keyword `kw` followed by a non-reserved identifier?
725
783
fn is_kw_followed_by_ident ( & self , kw : Symbol ) -> bool {
726
784
self . token . is_keyword ( kw) && self . look_ahead ( 1 , |t| t. is_ident ( ) && !t. is_reserved_ident ( ) )
@@ -1455,7 +1513,11 @@ impl<'a> Parser<'a> {
1455
1513
/// so emit a proper diagnostic.
1456
1514
// Public for rustfmt usage.
1457
1515
pub fn parse_visibility ( & mut self , fbt : FollowedByType ) -> PResult < ' a , Visibility > {
1458
- maybe_whole ! ( self , NtVis , |vis| vis. into_inner( ) ) ;
1516
+ if let Some ( vis) = self
1517
+ . eat_metavar_seq ( MetaVarKind :: Vis , |this| this. parse_visibility ( FollowedByType :: Yes ) )
1518
+ {
1519
+ return Ok ( vis) ;
1520
+ }
1459
1521
1460
1522
if !self . eat_keyword ( exp ! ( Pub ) ) {
1461
1523
// We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1683,7 +1745,9 @@ pub enum ParseNtResult {
1683
1745
Tt ( TokenTree ) ,
1684
1746
Ident ( Ident , IdentIsRaw ) ,
1685
1747
Lifetime ( Ident , IdentIsRaw ) ,
1748
+ Ty ( P < ast:: Ty > ) ,
1749
+ Vis ( P < ast:: Visibility > ) ,
1686
1750
1687
- /// This case will eventually be removed, along with `Token::Interpolate`.
1751
+ /// This variant will eventually be removed, along with `Token::Interpolate`.
1688
1752
Nt ( Arc < Nonterminal > ) ,
1689
1753
}
0 commit comments