@@ -116,12 +116,16 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
116
116
( $self: expr, $allow_qpath_recovery: expr) => {
117
117
if $allow_qpath_recovery
118
118
&& $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 )
122
121
{
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
+
125
129
return $self. maybe_recover_from_bad_qpath_stage_2( $self. prev_token. span, ty) ;
126
130
}
127
131
} ;
@@ -611,6 +615,24 @@ impl<'a> Parser<'a> {
611
615
self . token == * tok
612
616
}
613
617
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
+
614
636
/// Consumes a token 'tok' if it exists. Returns whether the given token was present.
615
637
///
616
638
/// the main purpose of this function is to reduce the cluttering of the suggestions list
@@ -720,6 +742,43 @@ impl<'a> Parser<'a> {
720
742
if !self . eat_keyword ( kw) { self . unexpected ( ) } else { Ok ( ( ) ) }
721
743
}
722
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 ( 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
+
723
782
/// Is the given keyword `kw` followed by a non-reserved identifier?
724
783
fn is_kw_followed_by_ident ( & self , kw : Symbol ) -> bool {
725
784
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> {
1461
1520
/// so emit a proper diagnostic.
1462
1521
// Public for rustfmt usage.
1463
1522
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
+ }
1465
1528
1466
1529
if !self . eat_keyword ( kw:: Pub ) {
1467
1530
// We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1699,7 +1762,9 @@ pub enum ParseNtResult {
1699
1762
Tt ( TokenTree ) ,
1700
1763
Ident ( Ident , IdentIsRaw ) ,
1701
1764
Lifetime ( Ident , IdentIsRaw ) ,
1765
+ Ty ( P < ast:: Ty > ) ,
1766
+ Vis ( P < ast:: Visibility > ) ,
1702
1767
1703
- /// This case will eventually be removed, along with `Token::Interpolate`.
1768
+ /// This variant will eventually be removed, along with `Token::Interpolate`.
1704
1769
Nt ( Lrc < Nonterminal > ) ,
1705
1770
}
0 commit comments