@@ -116,12 +116,16 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
116116 ( $self: expr, $allow_qpath_recovery: expr) => {
117117 if $allow_qpath_recovery
118118 && $self. may_recover( )
119- && $self. look_ahead( 1 , |t| t == & token:: PathSep )
120- && let token:: Interpolated ( nt) = & $self. token. kind
121- && let token:: NtTy ( ty) = & * * nt
119+ && let Some ( token:: MetaVarKind :: Ty ) = $self. token. is_metavar_seq( )
120+ && $self. check_noexpect_past_close_delim( & token:: PathSep )
122121 {
123- let ty = ty. clone( ) ;
124- $self. bump( ) ;
122+ // Reparse the type, then move to recovery.
123+ let ty = $self
124+ . eat_metavar_seq( token:: MetaVarKind :: Ty , |this| {
125+ this. parse_ty_no_question_mark_recover( )
126+ } )
127+ . expect( "metavar seq ty" ) ;
128+
125129 return $self. maybe_recover_from_bad_qpath_stage_2( $self. prev_token. span, ty) ;
126130 }
127131 } ;
@@ -611,6 +615,24 @@ impl<'a> Parser<'a> {
611615 self . token == * tok
612616 }
613617
618+ // Check the first token after the delimiter that closes the current
619+ // delimited sequence. (Panics if used in the outermost token stream, which
620+ // has no delimiters.) It uses a clone of the relevant tree cursor to skip
621+ // past the entire `TokenTree::Delimited` in a single step, avoiding the
622+ // need for unbounded token lookahead.
623+ //
624+ // Primarily used when `self.token` matches
625+ // `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
626+ // metavar expansion.
627+ fn check_noexpect_past_close_delim ( & self , tok : & TokenKind ) -> bool {
628+ let mut tree_cursor = self . token_cursor . stack . last ( ) . unwrap ( ) . 0 . clone ( ) ;
629+ let tt = tree_cursor. next_ref ( ) ;
630+ matches ! (
631+ tt,
632+ Some ( ast:: tokenstream:: TokenTree :: Token ( token:: Token { kind, .. } , _) ) if kind == tok
633+ )
634+ }
635+
614636 /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
615637 ///
616638 /// the main purpose of this function is to reduce the cluttering of the suggestions list
@@ -720,6 +742,43 @@ impl<'a> Parser<'a> {
720742 if !self . eat_keyword ( kw) { self . unexpected ( ) } else { Ok ( ( ) ) }
721743 }
722744
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 ( token:: 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 ( token:: 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+
723782 /// Is the given keyword `kw` followed by a non-reserved identifier?
724783 fn is_kw_followed_by_ident ( & self , kw : Symbol ) -> bool {
725784 self . token . is_keyword ( kw) && self . look_ahead ( 1 , |t| t. is_ident ( ) && !t. is_reserved_ident ( ) )
@@ -1461,7 +1520,11 @@ impl<'a> Parser<'a> {
14611520 /// so emit a proper diagnostic.
14621521 // Public for rustfmt usage.
14631522 pub fn parse_visibility ( & mut self , fbt : FollowedByType ) -> PResult < ' a , Visibility > {
1464- maybe_whole ! ( self , NtVis , |vis| vis. into_inner( ) ) ;
1523+ if let Some ( vis) = self
1524+ . eat_metavar_seq ( MetaVarKind :: Vis , |this| this. parse_visibility ( FollowedByType :: Yes ) )
1525+ {
1526+ return Ok ( vis) ;
1527+ }
14651528
14661529 if !self . eat_keyword ( kw:: Pub ) {
14671530 // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1699,7 +1762,9 @@ pub enum ParseNtResult {
16991762 Tt ( TokenTree ) ,
17001763 Ident ( Ident , IdentIsRaw ) ,
17011764 Lifetime ( Ident , IdentIsRaw ) ,
1765+ Ty ( P < ast:: Ty > ) ,
1766+ Vis ( P < ast:: Visibility > ) ,
17021767
1703- /// This case will eventually be removed, along with `Token::Interpolate`.
1768+ /// This variant will eventually be removed, along with `Token::Interpolate`.
17041769 Nt ( Lrc < Nonterminal > ) ,
17051770}
0 commit comments