@@ -117,12 +117,15 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
117117 ( $self: expr, $allow_qpath_recovery: expr) => {
118118 if $allow_qpath_recovery
119119 && $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 )
123123 {
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+
126129 return $self. maybe_recover_from_bad_qpath_stage_2( $self. prev_token. span, ty) ;
127130 }
128131 } ;
@@ -614,6 +617,24 @@ impl<'a> Parser<'a> {
614617 self . token == * tok
615618 }
616619
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+
617638 /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
618639 ///
619640 /// the main purpose of this function is to reduce the cluttering of the suggestions list
@@ -721,6 +742,43 @@ impl<'a> Parser<'a> {
721742 if !self . eat_keyword ( exp) { self . unexpected ( ) } else { Ok ( ( ) ) }
722743 }
723744
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+
724782 /// Is the given keyword `kw` followed by a non-reserved identifier?
725783 fn is_kw_followed_by_ident ( & self , kw : Symbol ) -> bool {
726784 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> {
14551513 /// so emit a proper diagnostic.
14561514 // Public for rustfmt usage.
14571515 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+ }
14591521
14601522 if !self . eat_keyword ( exp ! ( Pub ) ) {
14611523 // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1683,7 +1745,9 @@ pub enum ParseNtResult {
16831745 Tt ( TokenTree ) ,
16841746 Ident ( Ident , IdentIsRaw ) ,
16851747 Lifetime ( Ident , IdentIsRaw ) ,
1748+ Ty ( P < ast:: Ty > ) ,
1749+ Vis ( P < ast:: Visibility > ) ,
16861750
1687- /// This case will eventually be removed, along with `Token::Interpolate`.
1751+ /// This variant will eventually be removed, along with `Token::Interpolate`.
16881752 Nt ( Arc < Nonterminal > ) ,
16891753}
0 commit comments