@@ -154,6 +154,21 @@ macro_rules! maybe_whole {
154154 } ;
155155}
156156
157+ /// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`.
158+ macro_rules! maybe_recover_from_interpolated_ty_qpath {
159+ ( $self: expr, $allow_qpath_recovery: expr) => {
160+ if $allow_qpath_recovery && $self. look_ahead( 1 , |t| t == & token:: ModSep ) {
161+ if let token:: Interpolated ( nt) = & $self. token {
162+ if let token:: NtTy ( ty) = & * * nt {
163+ let ty = ty. clone( ) ;
164+ $self. bump( ) ;
165+ return $self. maybe_recover_from_bad_qpath_stage_2( $self. prev_span, ty) ;
166+ }
167+ }
168+ }
169+ }
170+ }
171+
157172fn maybe_append ( mut lhs : Vec < Attribute > , mut rhs : Option < Vec < Attribute > > ) -> Vec < Attribute > {
158173 if let Some ( ref mut rhs) = rhs {
159174 lhs. append ( rhs) ;
@@ -172,48 +187,38 @@ enum PrevTokenKind {
172187 Other ,
173188}
174189
175- trait RecoverQPath : Sized {
190+ trait RecoverQPath : Sized + ' static {
176191 const PATH_STYLE : PathStyle = PathStyle :: Expr ;
177192 fn to_ty ( & self ) -> Option < P < Ty > > ;
178- fn to_recovered ( & self , qself : Option < QSelf > , path : ast:: Path ) -> Self ;
179- fn to_string ( & self ) -> String ;
193+ fn recovered ( qself : Option < QSelf > , path : ast:: Path ) -> Self ;
180194}
181195
182196impl RecoverQPath for Ty {
183197 const PATH_STYLE : PathStyle = PathStyle :: Type ;
184198 fn to_ty ( & self ) -> Option < P < Ty > > {
185199 Some ( P ( self . clone ( ) ) )
186200 }
187- fn to_recovered ( & self , qself : Option < QSelf > , path : ast:: Path ) -> Self {
188- Self { span : path. span , node : TyKind :: Path ( qself, path) , id : self . id }
189- }
190- fn to_string ( & self ) -> String {
191- pprust:: ty_to_string ( self )
201+ fn recovered ( qself : Option < QSelf > , path : ast:: Path ) -> Self {
202+ Self { span : path. span , node : TyKind :: Path ( qself, path) , id : ast:: DUMMY_NODE_ID }
192203 }
193204}
194205
195206impl RecoverQPath for Pat {
196207 fn to_ty ( & self ) -> Option < P < Ty > > {
197208 self . to_ty ( )
198209 }
199- fn to_recovered ( & self , qself : Option < QSelf > , path : ast:: Path ) -> Self {
200- Self { span : path. span , node : PatKind :: Path ( qself, path) , id : self . id }
201- }
202- fn to_string ( & self ) -> String {
203- pprust:: pat_to_string ( self )
210+ fn recovered ( qself : Option < QSelf > , path : ast:: Path ) -> Self {
211+ Self { span : path. span , node : PatKind :: Path ( qself, path) , id : ast:: DUMMY_NODE_ID }
204212 }
205213}
206214
207215impl RecoverQPath for Expr {
208216 fn to_ty ( & self ) -> Option < P < Ty > > {
209217 self . to_ty ( )
210218 }
211- fn to_recovered ( & self , qself : Option < QSelf > , path : ast:: Path ) -> Self {
219+ fn recovered ( qself : Option < QSelf > , path : ast:: Path ) -> Self {
212220 Self { span : path. span , node : ExprKind :: Path ( qself, path) ,
213- id : self . id , attrs : self . attrs . clone ( ) }
214- }
215- fn to_string ( & self ) -> String {
216- pprust:: expr_to_string ( self )
221+ attrs : ThinVec :: new ( ) , id : ast:: DUMMY_NODE_ID }
217222 }
218223}
219224
@@ -1651,6 +1656,7 @@ impl<'a> Parser<'a> {
16511656
16521657 fn parse_ty_common ( & mut self , allow_plus : bool , allow_qpath_recovery : bool ,
16531658 allow_c_variadic : bool ) -> PResult < ' a , P < Ty > > {
1659+ maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
16541660 maybe_whole ! ( self , NtTy , |x| x) ;
16551661
16561662 let lo = self . span ;
@@ -1802,14 +1808,12 @@ impl<'a> Parser<'a> {
18021808 } ;
18031809
18041810 let span = lo. to ( self . prev_span ) ;
1805- let ty = Ty { node, span, id : ast:: DUMMY_NODE_ID } ;
1811+ let ty = P ( Ty { node, span, id : ast:: DUMMY_NODE_ID } ) ;
18061812
18071813 // Try to recover from use of `+` with incorrect priority.
18081814 self . maybe_report_ambiguous_plus ( allow_plus, impl_dyn_multi, & ty) ;
18091815 self . maybe_recover_from_bad_type_plus ( allow_plus, & ty) ?;
1810- let ty = self . maybe_recover_from_bad_qpath ( ty, allow_qpath_recovery) ?;
1811-
1812- Ok ( P ( ty) )
1816+ self . maybe_recover_from_bad_qpath ( ty, allow_qpath_recovery)
18131817 }
18141818
18151819 fn parse_remaining_bounds ( & mut self , generic_params : Vec < GenericParam > , path : ast:: Path ,
@@ -1881,35 +1885,35 @@ impl<'a> Parser<'a> {
18811885 }
18821886
18831887 // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
1884- fn maybe_recover_from_bad_qpath < T : RecoverQPath > ( & mut self , base : T , allow_recovery : bool )
1885- -> PResult < ' a , T > {
1888+ fn maybe_recover_from_bad_qpath < T : RecoverQPath > ( & mut self , base : P < T > , allow_recovery : bool )
1889+ -> PResult < ' a , P < T > > {
18861890 // Do not add `::` to expected tokens.
1887- if !allow_recovery || self . token != token:: ModSep {
1888- return Ok ( base) ;
1891+ if allow_recovery && self . token == token:: ModSep {
1892+ if let Some ( ty) = base. to_ty ( ) {
1893+ return self . maybe_recover_from_bad_qpath_stage_2 ( ty. span , ty) ;
1894+ }
18891895 }
1890- let ty = match base. to_ty ( ) {
1891- Some ( ty) => ty,
1892- None => return Ok ( base) ,
1893- } ;
1896+ Ok ( base)
1897+ }
18941898
1895- self . bump ( ) ; // `::`
1896- let mut segments = Vec :: new ( ) ;
1897- self . parse_path_segments ( & mut segments , T :: PATH_STYLE , true ) ?;
1899+ fn maybe_recover_from_bad_qpath_stage_2 < T : RecoverQPath > ( & mut self , ty_span : Span , ty : P < Ty > )
1900+ -> PResult < ' a , P < T > > {
1901+ self . expect ( & token :: ModSep ) ?;
18981902
1899- let span = ty. span . to ( self . prev_span ) ;
1900- let path_span = span. to ( span) ; // use an empty path since `position` == 0
1901- let recovered = base. to_recovered (
1902- Some ( QSelf { ty, path_span, position : 0 } ) ,
1903- ast:: Path { segments, span } ,
1904- ) ;
1903+ let mut path = ast:: Path { segments : Vec :: new ( ) , span : syntax_pos:: DUMMY_SP } ;
1904+ self . parse_path_segments ( & mut path. segments , T :: PATH_STYLE , true ) ?;
1905+ path. span = ty_span. to ( self . prev_span ) ;
19051906
1907+ let ty_str = self . sess . source_map ( ) . span_to_snippet ( ty_span)
1908+ . unwrap_or_else ( |_| pprust:: ty_to_string ( & ty) ) ;
19061909 self . diagnostic ( )
1907- . struct_span_err ( span, "missing angle brackets in associated item path" )
1910+ . struct_span_err ( path . span , "missing angle brackets in associated item path" )
19081911 . span_suggestion ( // this is a best-effort recovery
1909- span, "try" , recovered . to_string ( ) , Applicability :: MaybeIncorrect
1912+ path . span , "try" , format ! ( "<{}>::{}" , ty_str , path ) , Applicability :: MaybeIncorrect
19101913 ) . emit ( ) ;
19111914
1912- Ok ( recovered)
1915+ let path_span = path. span . to ( path. span ) ; // use an empty path since `position` == 0
1916+ Ok ( P ( T :: recovered ( Some ( QSelf { ty, path_span, position : 0 } ) , path) ) )
19131917 }
19141918
19151919 fn parse_borrowed_pointee ( & mut self ) -> PResult < ' a , TyKind > {
@@ -2574,15 +2578,6 @@ impl<'a> Parser<'a> {
25742578 ExprKind :: AssignOp ( binop, lhs, rhs)
25752579 }
25762580
2577- pub fn mk_mac_expr ( & mut self , span : Span , m : Mac_ , attrs : ThinVec < Attribute > ) -> P < Expr > {
2578- P ( Expr {
2579- id : ast:: DUMMY_NODE_ID ,
2580- node : ExprKind :: Mac ( source_map:: Spanned { node : m, span : span} ) ,
2581- span,
2582- attrs,
2583- } )
2584- }
2585-
25862581 fn expect_delimited_token_tree ( & mut self ) -> PResult < ' a , ( MacDelimiter , TokenStream ) > {
25872582 let delim = match self . token {
25882583 token:: OpenDelim ( delim) => delim,
@@ -2612,6 +2607,7 @@ impl<'a> Parser<'a> {
26122607 /// N.B., this does not parse outer attributes, and is private because it only works
26132608 /// correctly if called from `parse_dot_or_call_expr()`.
26142609 fn parse_bottom_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
2610+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
26152611 maybe_whole_expr ! ( self ) ;
26162612
26172613 // Outer attributes are already parsed and will be
@@ -2826,29 +2822,23 @@ impl<'a> Parser<'a> {
28262822 db. note ( "variable declaration using `let` is a statement" ) ;
28272823 return Err ( db) ;
28282824 } else if self . token . is_path_start ( ) {
2829- let pth = self . parse_path ( PathStyle :: Expr ) ?;
2825+ let path = self . parse_path ( PathStyle :: Expr ) ?;
28302826
28312827 // `!`, as an operator, is prefix, so we know this isn't that
28322828 if self . eat ( & token:: Not ) {
28332829 // MACRO INVOCATION expression
28342830 let ( delim, tts) = self . expect_delimited_token_tree ( ) ?;
2835- let hi = self . prev_span ;
2836- let node = Mac_ { path : pth, tts, delim } ;
2837- return Ok ( self . mk_mac_expr ( lo. to ( hi) , node, attrs) )
2838- }
2839- if self . check ( & token:: OpenDelim ( token:: Brace ) ) {
2831+ hi = self . prev_span ;
2832+ ex = ExprKind :: Mac ( respan ( lo. to ( hi) , Mac_ { path, tts, delim } ) ) ;
2833+ } else if self . check ( & token:: OpenDelim ( token:: Brace ) ) &&
2834+ !self . restrictions . contains ( Restrictions :: NO_STRUCT_LITERAL ) {
28402835 // This is a struct literal, unless we're prohibited
28412836 // from parsing struct literals here.
2842- let prohibited = self . restrictions . contains (
2843- Restrictions :: NO_STRUCT_LITERAL
2844- ) ;
2845- if !prohibited {
2846- return self . parse_struct_expr ( lo, pth, attrs) ;
2847- }
2837+ return self . parse_struct_expr ( lo, path, attrs) ;
2838+ } else {
2839+ hi = path. span ;
2840+ ex = ExprKind :: Path ( None , path) ;
28482841 }
2849-
2850- hi = pth. span ;
2851- ex = ExprKind :: Path ( None , pth) ;
28522842 } else {
28532843 if !self . unclosed_delims . is_empty ( ) && self . check ( & token:: Semi ) {
28542844 // Don't complain about bare semicolons after unclosed braces
@@ -2883,10 +2873,8 @@ impl<'a> Parser<'a> {
28832873 }
28842874 }
28852875
2886- let expr = Expr { node : ex, span : lo. to ( hi) , id : ast:: DUMMY_NODE_ID , attrs } ;
2887- let expr = self . maybe_recover_from_bad_qpath ( expr, true ) ?;
2888-
2889- return Ok ( P ( expr) ) ;
2876+ let expr = self . mk_expr ( lo. to ( hi) , ex, attrs) ;
2877+ self . maybe_recover_from_bad_qpath ( expr, true )
28902878 }
28912879
28922880 fn parse_struct_expr ( & mut self , lo : Span , pth : ast:: Path , mut attrs : ThinVec < Attribute > )
@@ -4581,6 +4569,7 @@ impl<'a> Parser<'a> {
45814569 allow_range_pat : bool ,
45824570 expected : Option < & ' static str > ,
45834571 ) -> PResult < ' a , P < Pat > > {
4572+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
45844573 maybe_whole ! ( self , NtPat , |x| x) ;
45854574
45864575 let lo = self . span ;
@@ -4756,7 +4745,7 @@ impl<'a> Parser<'a> {
47564745 }
47574746 }
47584747
4759- let pat = Pat { node : pat, span : lo. to ( self . prev_span ) , id : ast:: DUMMY_NODE_ID } ;
4748+ let pat = P ( Pat { node : pat, span : lo. to ( self . prev_span ) , id : ast:: DUMMY_NODE_ID } ) ;
47604749 let pat = self . maybe_recover_from_bad_qpath ( pat, true ) ?;
47614750
47624751 if !allow_range_pat {
@@ -4782,7 +4771,7 @@ impl<'a> Parser<'a> {
47824771 }
47834772 }
47844773
4785- Ok ( P ( pat) )
4774+ Ok ( pat)
47864775 }
47874776
47884777 /// Parses `ident` or `ident @ pat`.
@@ -5250,7 +5239,8 @@ impl<'a> Parser<'a> {
52505239 self . warn_missing_semicolon ( ) ;
52515240 StmtKind :: Mac ( P ( ( mac, style, attrs. into ( ) ) ) )
52525241 } else {
5253- let e = self . mk_mac_expr ( lo. to ( hi) , mac. node , ThinVec :: new ( ) ) ;
5242+ let e = self . mk_expr ( mac. span , ExprKind :: Mac ( mac) , ThinVec :: new ( ) ) ;
5243+ let e = self . maybe_recover_from_bad_qpath ( e, true ) ?;
52545244 let e = self . parse_dot_or_call_expr_with ( e, lo, attrs. into ( ) ) ?;
52555245 let e = self . parse_assoc_expr_with ( 0 , LhsExpr :: AlreadyParsed ( e) ) ?;
52565246 StmtKind :: Expr ( e)
0 commit comments