@@ -118,23 +118,22 @@ enum BlockMode {
118118/// `token::Interpolated` tokens.
119119macro_rules! maybe_whole_expr {
120120 ( $p: expr) => {
121- if let token:: Interpolated ( nt) = $p. token. clone( ) {
122- match * nt {
123- token:: NtExpr ( ref e) | token:: NtLiteral ( ref e) => {
121+ if let token:: Interpolated ( nt) = & $p. token {
122+ match & * * nt {
123+ token:: NtExpr ( e) | token:: NtLiteral ( e) => {
124+ let e = e. clone( ) ;
124125 $p. bump( ) ;
125- return Ok ( ( * e ) . clone ( ) ) ;
126+ return Ok ( e ) ;
126127 }
127- token:: NtPath ( ref path) => {
128+ token:: NtPath ( path) => {
129+ let path = path. clone( ) ;
128130 $p. bump( ) ;
129- let span = $p. span;
130- let kind = ExprKind :: Path ( None , ( * path) . clone( ) ) ;
131- return Ok ( $p. mk_expr( span, kind, ThinVec :: new( ) ) ) ;
131+ return Ok ( $p. mk_expr( $p. span, ExprKind :: Path ( None , path) , ThinVec :: new( ) ) ) ;
132132 }
133- token:: NtBlock ( ref block) => {
133+ token:: NtBlock ( block) => {
134+ let block = block. clone( ) ;
134135 $p. bump( ) ;
135- let span = $p. span;
136- let kind = ExprKind :: Block ( ( * block) . clone( ) , None ) ;
137- return Ok ( $p. mk_expr( span, kind, ThinVec :: new( ) ) ) ;
136+ return Ok ( $p. mk_expr( $p. span, ExprKind :: Block ( block, None ) , ThinVec :: new( ) ) ) ;
138137 }
139138 _ => { } ,
140139 } ;
@@ -145,15 +144,31 @@ macro_rules! maybe_whole_expr {
145144/// As maybe_whole_expr, but for things other than expressions
146145macro_rules! maybe_whole {
147146 ( $p: expr, $constructor: ident, |$x: ident| $e: expr) => {
148- if let token:: Interpolated ( nt) = $p. token. clone( ) {
149- if let token:: $constructor( $x) = ( * nt) . clone( ) {
147+ if let token:: Interpolated ( nt) = & $p. token {
148+ if let token:: $constructor( x) = & * * nt {
149+ let $x = x. clone( ) ;
150150 $p. bump( ) ;
151151 return Ok ( $e) ;
152152 }
153153 }
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
@@ -1649,6 +1654,7 @@ impl<'a> Parser<'a> {
16491654
16501655 fn parse_ty_common ( & mut self , allow_plus : bool , allow_qpath_recovery : bool ,
16511656 allow_c_variadic : bool ) -> PResult < ' a , P < Ty > > {
1657+ maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
16521658 maybe_whole ! ( self , NtTy , |x| x) ;
16531659
16541660 let lo = self . span ;
@@ -1800,14 +1806,12 @@ impl<'a> Parser<'a> {
18001806 } ;
18011807
18021808 let span = lo. to ( self . prev_span ) ;
1803- let ty = Ty { node, span, id : ast:: DUMMY_NODE_ID } ;
1809+ let ty = P ( Ty { node, span, id : ast:: DUMMY_NODE_ID } ) ;
18041810
18051811 // Try to recover from use of `+` with incorrect priority.
18061812 self . maybe_report_ambiguous_plus ( allow_plus, impl_dyn_multi, & ty) ;
18071813 self . maybe_recover_from_bad_type_plus ( allow_plus, & ty) ?;
1808- let ty = self . maybe_recover_from_bad_qpath ( ty, allow_qpath_recovery) ?;
1809-
1810- Ok ( P ( ty) )
1814+ self . maybe_recover_from_bad_qpath ( ty, allow_qpath_recovery)
18111815 }
18121816
18131817 fn parse_remaining_bounds ( & mut self , generic_params : Vec < GenericParam > , path : ast:: Path ,
@@ -1878,36 +1882,40 @@ impl<'a> Parser<'a> {
18781882 Ok ( ( ) )
18791883 }
18801884
1881- // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
1882- fn maybe_recover_from_bad_qpath < T : RecoverQPath > ( & mut self , base : T , allow_recovery : bool )
1883- -> PResult < ' a , T > {
1885+ /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
1886+ /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
1887+ /// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
1888+ fn maybe_recover_from_bad_qpath < T : RecoverQPath > ( & mut self , base : P < T > , allow_recovery : bool )
1889+ -> PResult < ' a , P < T > > {
18841890 // Do not add `::` to expected tokens.
1885- if !allow_recovery || self . token != token:: ModSep {
1886- 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+ }
18871895 }
1888- let ty = match base. to_ty ( ) {
1889- Some ( ty) => ty,
1890- None => return Ok ( base) ,
1891- } ;
1896+ Ok ( base)
1897+ }
18921898
1893- self . bump ( ) ; // `::`
1894- let mut segments = Vec :: new ( ) ;
1895- self . parse_path_segments ( & mut segments, T :: PATH_STYLE , true ) ?;
1899+ /// Given an already parsed `Ty` parse the `::AssocItem` tail and
1900+ /// combine them into a `<Ty>::AssocItem` expression/pattern/type.
1901+ fn maybe_recover_from_bad_qpath_stage_2 < T : RecoverQPath > ( & mut self , ty_span : Span , ty : P < Ty > )
1902+ -> PResult < ' a , P < T > > {
1903+ self . expect ( & token:: ModSep ) ?;
18961904
1897- let span = ty. span . to ( self . prev_span ) ;
1898- let path_span = span. to ( span) ; // use an empty path since `position` == 0
1899- let recovered = base. to_recovered (
1900- Some ( QSelf { ty, path_span, position : 0 } ) ,
1901- ast:: Path { segments, span } ,
1902- ) ;
1905+ let mut path = ast:: Path { segments : Vec :: new ( ) , span : syntax_pos:: DUMMY_SP } ;
1906+ self . parse_path_segments ( & mut path. segments , T :: PATH_STYLE , true ) ?;
1907+ path. span = ty_span. to ( self . prev_span ) ;
19031908
1909+ let ty_str = self . sess . source_map ( ) . span_to_snippet ( ty_span)
1910+ . unwrap_or_else ( |_| pprust:: ty_to_string ( & ty) ) ;
19041911 self . diagnostic ( )
1905- . struct_span_err ( span, "missing angle brackets in associated item path" )
1912+ . struct_span_err ( path . span , "missing angle brackets in associated item path" )
19061913 . span_suggestion ( // this is a best-effort recovery
1907- span, "try" , recovered . to_string ( ) , Applicability :: MaybeIncorrect
1914+ path . span , "try" , format ! ( "<{}>::{}" , ty_str , path ) , Applicability :: MaybeIncorrect
19081915 ) . emit ( ) ;
19091916
1910- Ok ( recovered)
1917+ let path_span = ty_span. shrink_to_hi ( ) ; // use an empty path since `position` == 0
1918+ Ok ( P ( T :: recovered ( Some ( QSelf { ty, path_span, position : 0 } ) , path) ) )
19111919 }
19121920
19131921 fn parse_borrowed_pointee ( & mut self ) -> PResult < ' a , TyKind > {
@@ -2572,15 +2580,6 @@ impl<'a> Parser<'a> {
25722580 ExprKind :: AssignOp ( binop, lhs, rhs)
25732581 }
25742582
2575- pub fn mk_mac_expr ( & mut self , span : Span , m : Mac_ , attrs : ThinVec < Attribute > ) -> P < Expr > {
2576- P ( Expr {
2577- id : ast:: DUMMY_NODE_ID ,
2578- node : ExprKind :: Mac ( source_map:: Spanned { node : m, span : span} ) ,
2579- span,
2580- attrs,
2581- } )
2582- }
2583-
25842583 fn expect_delimited_token_tree ( & mut self ) -> PResult < ' a , ( MacDelimiter , TokenStream ) > {
25852584 let delim = match self . token {
25862585 token:: OpenDelim ( delim) => delim,
@@ -2610,6 +2609,7 @@ impl<'a> Parser<'a> {
26102609 /// N.B., this does not parse outer attributes, and is private because it only works
26112610 /// correctly if called from `parse_dot_or_call_expr()`.
26122611 fn parse_bottom_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
2612+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
26132613 maybe_whole_expr ! ( self ) ;
26142614
26152615 // Outer attributes are already parsed and will be
@@ -2824,29 +2824,23 @@ impl<'a> Parser<'a> {
28242824 db. note ( "variable declaration using `let` is a statement" ) ;
28252825 return Err ( db) ;
28262826 } else if self . token . is_path_start ( ) {
2827- let pth = self . parse_path ( PathStyle :: Expr ) ?;
2827+ let path = self . parse_path ( PathStyle :: Expr ) ?;
28282828
28292829 // `!`, as an operator, is prefix, so we know this isn't that
28302830 if self . eat ( & token:: Not ) {
28312831 // MACRO INVOCATION expression
28322832 let ( delim, tts) = self . expect_delimited_token_tree ( ) ?;
2833- let hi = self . prev_span ;
2834- let node = Mac_ { path : pth, tts, delim } ;
2835- return Ok ( self . mk_mac_expr ( lo. to ( hi) , node, attrs) )
2836- }
2837- if self . check ( & token:: OpenDelim ( token:: Brace ) ) {
2833+ hi = self . prev_span ;
2834+ ex = ExprKind :: Mac ( respan ( lo. to ( hi) , Mac_ { path, tts, delim } ) ) ;
2835+ } else if self . check ( & token:: OpenDelim ( token:: Brace ) ) &&
2836+ !self . restrictions . contains ( Restrictions :: NO_STRUCT_LITERAL ) {
28382837 // This is a struct literal, unless we're prohibited
28392838 // from parsing struct literals here.
2840- let prohibited = self . restrictions . contains (
2841- Restrictions :: NO_STRUCT_LITERAL
2842- ) ;
2843- if !prohibited {
2844- return self . parse_struct_expr ( lo, pth, attrs) ;
2845- }
2839+ return self . parse_struct_expr ( lo, path, attrs) ;
2840+ } else {
2841+ hi = path. span ;
2842+ ex = ExprKind :: Path ( None , path) ;
28462843 }
2847-
2848- hi = pth. span ;
2849- ex = ExprKind :: Path ( None , pth) ;
28502844 } else {
28512845 if !self . unclosed_delims . is_empty ( ) && self . check ( & token:: Semi ) {
28522846 // Don't complain about bare semicolons after unclosed braces
@@ -2881,10 +2875,8 @@ impl<'a> Parser<'a> {
28812875 }
28822876 }
28832877
2884- let expr = Expr { node : ex, span : lo. to ( hi) , id : ast:: DUMMY_NODE_ID , attrs } ;
2885- let expr = self . maybe_recover_from_bad_qpath ( expr, true ) ?;
2886-
2887- return Ok ( P ( expr) ) ;
2878+ let expr = self . mk_expr ( lo. to ( hi) , ex, attrs) ;
2879+ self . maybe_recover_from_bad_qpath ( expr, true )
28882880 }
28892881
28902882 fn parse_struct_expr ( & mut self , lo : Span , pth : ast:: Path , mut attrs : ThinVec < Attribute > )
@@ -4584,6 +4576,7 @@ impl<'a> Parser<'a> {
45844576 allow_range_pat : bool ,
45854577 expected : Option < & ' static str > ,
45864578 ) -> PResult < ' a , P < Pat > > {
4579+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
45874580 maybe_whole ! ( self , NtPat , |x| x) ;
45884581
45894582 let lo = self . span ;
@@ -4759,7 +4752,7 @@ impl<'a> Parser<'a> {
47594752 }
47604753 }
47614754
4762- let pat = Pat { node : pat, span : lo. to ( self . prev_span ) , id : ast:: DUMMY_NODE_ID } ;
4755+ let pat = P ( Pat { node : pat, span : lo. to ( self . prev_span ) , id : ast:: DUMMY_NODE_ID } ) ;
47634756 let pat = self . maybe_recover_from_bad_qpath ( pat, true ) ?;
47644757
47654758 if !allow_range_pat {
@@ -4785,7 +4778,7 @@ impl<'a> Parser<'a> {
47854778 }
47864779 }
47874780
4788- Ok ( P ( pat) )
4781+ Ok ( pat)
47894782 }
47904783
47914784 /// Parses `ident` or `ident @ pat`.
@@ -5249,7 +5242,8 @@ impl<'a> Parser<'a> {
52495242 self . warn_missing_semicolon ( ) ;
52505243 StmtKind :: Mac ( P ( ( mac, style, attrs. into ( ) ) ) )
52515244 } else {
5252- let e = self . mk_mac_expr ( lo. to ( hi) , mac. node , ThinVec :: new ( ) ) ;
5245+ let e = self . mk_expr ( mac. span , ExprKind :: Mac ( mac) , ThinVec :: new ( ) ) ;
5246+ let e = self . maybe_recover_from_bad_qpath ( e, true ) ?;
52535247 let e = self . parse_dot_or_call_expr_with ( e, lo, attrs. into ( ) ) ?;
52545248 let e = self . parse_assoc_expr_with ( 0 , LhsExpr :: AlreadyParsed ( e) ) ?;
52555249 StmtKind :: Expr ( e)
0 commit comments