@@ -154,6 +154,21 @@ macro_rules! maybe_whole {
154
154
} ;
155
155
}
156
156
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
+
157
172
fn maybe_append ( mut lhs : Vec < Attribute > , mut rhs : Option < Vec < Attribute > > ) -> Vec < Attribute > {
158
173
if let Some ( ref mut rhs) = rhs {
159
174
lhs. append ( rhs) ;
@@ -172,48 +187,38 @@ enum PrevTokenKind {
172
187
Other ,
173
188
}
174
189
175
- trait RecoverQPath : Sized {
190
+ trait RecoverQPath : Sized + ' static {
176
191
const PATH_STYLE : PathStyle = PathStyle :: Expr ;
177
192
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 ;
180
194
}
181
195
182
196
impl RecoverQPath for Ty {
183
197
const PATH_STYLE : PathStyle = PathStyle :: Type ;
184
198
fn to_ty ( & self ) -> Option < P < Ty > > {
185
199
Some ( P ( self . clone ( ) ) )
186
200
}
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 }
192
203
}
193
204
}
194
205
195
206
impl RecoverQPath for Pat {
196
207
fn to_ty ( & self ) -> Option < P < Ty > > {
197
208
self . to_ty ( )
198
209
}
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 }
204
212
}
205
213
}
206
214
207
215
impl RecoverQPath for Expr {
208
216
fn to_ty ( & self ) -> Option < P < Ty > > {
209
217
self . to_ty ( )
210
218
}
211
- fn to_recovered ( & self , qself : Option < QSelf > , path : ast:: Path ) -> Self {
219
+ fn recovered ( qself : Option < QSelf > , path : ast:: Path ) -> Self {
212
220
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 }
217
222
}
218
223
}
219
224
@@ -1651,6 +1656,7 @@ impl<'a> Parser<'a> {
1651
1656
1652
1657
fn parse_ty_common ( & mut self , allow_plus : bool , allow_qpath_recovery : bool ,
1653
1658
allow_c_variadic : bool ) -> PResult < ' a , P < Ty > > {
1659
+ maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
1654
1660
maybe_whole ! ( self , NtTy , |x| x) ;
1655
1661
1656
1662
let lo = self . span ;
@@ -1802,14 +1808,12 @@ impl<'a> Parser<'a> {
1802
1808
} ;
1803
1809
1804
1810
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 } ) ;
1806
1812
1807
1813
// Try to recover from use of `+` with incorrect priority.
1808
1814
self . maybe_report_ambiguous_plus ( allow_plus, impl_dyn_multi, & ty) ;
1809
1815
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)
1813
1817
}
1814
1818
1815
1819
fn parse_remaining_bounds ( & mut self , generic_params : Vec < GenericParam > , path : ast:: Path ,
@@ -1881,35 +1885,35 @@ impl<'a> Parser<'a> {
1881
1885
}
1882
1886
1883
1887
// 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 > > {
1886
1890
// 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
+ }
1889
1895
}
1890
- let ty = match base. to_ty ( ) {
1891
- Some ( ty) => ty,
1892
- None => return Ok ( base) ,
1893
- } ;
1896
+ Ok ( base)
1897
+ }
1894
1898
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 ) ?;
1898
1902
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 ) ;
1905
1906
1907
+ let ty_str = self . sess . source_map ( ) . span_to_snippet ( ty_span)
1908
+ . unwrap_or_else ( |_| pprust:: ty_to_string ( & ty) ) ;
1906
1909
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" )
1908
1911
. 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
1910
1913
) . emit ( ) ;
1911
1914
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) ) )
1913
1917
}
1914
1918
1915
1919
fn parse_borrowed_pointee ( & mut self ) -> PResult < ' a , TyKind > {
@@ -2574,15 +2578,6 @@ impl<'a> Parser<'a> {
2574
2578
ExprKind :: AssignOp ( binop, lhs, rhs)
2575
2579
}
2576
2580
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
-
2586
2581
fn expect_delimited_token_tree ( & mut self ) -> PResult < ' a , ( MacDelimiter , TokenStream ) > {
2587
2582
let delim = match self . token {
2588
2583
token:: OpenDelim ( delim) => delim,
@@ -2612,6 +2607,7 @@ impl<'a> Parser<'a> {
2612
2607
/// N.B., this does not parse outer attributes, and is private because it only works
2613
2608
/// correctly if called from `parse_dot_or_call_expr()`.
2614
2609
fn parse_bottom_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
2610
+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
2615
2611
maybe_whole_expr ! ( self ) ;
2616
2612
2617
2613
// Outer attributes are already parsed and will be
@@ -2826,29 +2822,23 @@ impl<'a> Parser<'a> {
2826
2822
db. note ( "variable declaration using `let` is a statement" ) ;
2827
2823
return Err ( db) ;
2828
2824
} else if self . token . is_path_start ( ) {
2829
- let pth = self . parse_path ( PathStyle :: Expr ) ?;
2825
+ let path = self . parse_path ( PathStyle :: Expr ) ?;
2830
2826
2831
2827
// `!`, as an operator, is prefix, so we know this isn't that
2832
2828
if self . eat ( & token:: Not ) {
2833
2829
// MACRO INVOCATION expression
2834
2830
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 ) {
2840
2835
// This is a struct literal, unless we're prohibited
2841
2836
// 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) ;
2848
2841
}
2849
-
2850
- hi = pth. span ;
2851
- ex = ExprKind :: Path ( None , pth) ;
2852
2842
} else {
2853
2843
if !self . unclosed_delims . is_empty ( ) && self . check ( & token:: Semi ) {
2854
2844
// Don't complain about bare semicolons after unclosed braces
@@ -2883,10 +2873,8 @@ impl<'a> Parser<'a> {
2883
2873
}
2884
2874
}
2885
2875
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 )
2890
2878
}
2891
2879
2892
2880
fn parse_struct_expr ( & mut self , lo : Span , pth : ast:: Path , mut attrs : ThinVec < Attribute > )
@@ -4581,6 +4569,7 @@ impl<'a> Parser<'a> {
4581
4569
allow_range_pat : bool ,
4582
4570
expected : Option < & ' static str > ,
4583
4571
) -> PResult < ' a , P < Pat > > {
4572
+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
4584
4573
maybe_whole ! ( self , NtPat , |x| x) ;
4585
4574
4586
4575
let lo = self . span ;
@@ -4756,7 +4745,7 @@ impl<'a> Parser<'a> {
4756
4745
}
4757
4746
}
4758
4747
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 } ) ;
4760
4749
let pat = self . maybe_recover_from_bad_qpath ( pat, true ) ?;
4761
4750
4762
4751
if !allow_range_pat {
@@ -4782,7 +4771,7 @@ impl<'a> Parser<'a> {
4782
4771
}
4783
4772
}
4784
4773
4785
- Ok ( P ( pat) )
4774
+ Ok ( pat)
4786
4775
}
4787
4776
4788
4777
/// Parses `ident` or `ident @ pat`.
@@ -5250,7 +5239,8 @@ impl<'a> Parser<'a> {
5250
5239
self . warn_missing_semicolon ( ) ;
5251
5240
StmtKind :: Mac ( P ( ( mac, style, attrs. into ( ) ) ) )
5252
5241
} 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 ) ?;
5254
5244
let e = self . parse_dot_or_call_expr_with ( e, lo, attrs. into ( ) ) ?;
5255
5245
let e = self . parse_assoc_expr_with ( 0 , LhsExpr :: AlreadyParsed ( e) ) ?;
5256
5246
StmtKind :: Expr ( e)
0 commit comments