@@ -118,23 +118,22 @@ enum BlockMode {
118
118
/// `token::Interpolated` tokens.
119
119
macro_rules! maybe_whole_expr {
120
120
( $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( ) ;
124
125
$p. bump( ) ;
125
- return Ok ( ( * e ) . clone ( ) ) ;
126
+ return Ok ( e ) ;
126
127
}
127
- token:: NtPath ( ref path) => {
128
+ token:: NtPath ( path) => {
129
+ let path = path. clone( ) ;
128
130
$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( ) ) ) ;
132
132
}
133
- token:: NtBlock ( ref block) => {
133
+ token:: NtBlock ( block) => {
134
+ let block = block. clone( ) ;
134
135
$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( ) ) ) ;
138
137
}
139
138
_ => { } ,
140
139
} ;
@@ -145,15 +144,31 @@ macro_rules! maybe_whole_expr {
145
144
/// As maybe_whole_expr, but for things other than expressions
146
145
macro_rules! maybe_whole {
147
146
( $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( ) ;
150
150
$p. bump( ) ;
151
151
return Ok ( $e) ;
152
152
}
153
153
}
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
@@ -1649,6 +1654,7 @@ impl<'a> Parser<'a> {
1649
1654
1650
1655
fn parse_ty_common ( & mut self , allow_plus : bool , allow_qpath_recovery : bool ,
1651
1656
allow_c_variadic : bool ) -> PResult < ' a , P < Ty > > {
1657
+ maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
1652
1658
maybe_whole ! ( self , NtTy , |x| x) ;
1653
1659
1654
1660
let lo = self . span ;
@@ -1800,14 +1806,12 @@ impl<'a> Parser<'a> {
1800
1806
} ;
1801
1807
1802
1808
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 } ) ;
1804
1810
1805
1811
// Try to recover from use of `+` with incorrect priority.
1806
1812
self . maybe_report_ambiguous_plus ( allow_plus, impl_dyn_multi, & ty) ;
1807
1813
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)
1811
1815
}
1812
1816
1813
1817
fn parse_remaining_bounds ( & mut self , generic_params : Vec < GenericParam > , path : ast:: Path ,
@@ -1878,36 +1882,40 @@ impl<'a> Parser<'a> {
1878
1882
Ok ( ( ) )
1879
1883
}
1880
1884
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 > > {
1884
1890
// 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
+ }
1887
1895
}
1888
- let ty = match base. to_ty ( ) {
1889
- Some ( ty) => ty,
1890
- None => return Ok ( base) ,
1891
- } ;
1896
+ Ok ( base)
1897
+ }
1892
1898
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 ) ?;
1896
1904
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 ) ;
1903
1908
1909
+ let ty_str = self . sess . source_map ( ) . span_to_snippet ( ty_span)
1910
+ . unwrap_or_else ( |_| pprust:: ty_to_string ( & ty) ) ;
1904
1911
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" )
1906
1913
. 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
1908
1915
) . emit ( ) ;
1909
1916
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) ) )
1911
1919
}
1912
1920
1913
1921
fn parse_borrowed_pointee ( & mut self ) -> PResult < ' a , TyKind > {
@@ -2572,15 +2580,6 @@ impl<'a> Parser<'a> {
2572
2580
ExprKind :: AssignOp ( binop, lhs, rhs)
2573
2581
}
2574
2582
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
-
2584
2583
fn expect_delimited_token_tree ( & mut self ) -> PResult < ' a , ( MacDelimiter , TokenStream ) > {
2585
2584
let delim = match self . token {
2586
2585
token:: OpenDelim ( delim) => delim,
@@ -2610,6 +2609,7 @@ impl<'a> Parser<'a> {
2610
2609
/// N.B., this does not parse outer attributes, and is private because it only works
2611
2610
/// correctly if called from `parse_dot_or_call_expr()`.
2612
2611
fn parse_bottom_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
2612
+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
2613
2613
maybe_whole_expr ! ( self ) ;
2614
2614
2615
2615
// Outer attributes are already parsed and will be
@@ -2824,29 +2824,23 @@ impl<'a> Parser<'a> {
2824
2824
db. note ( "variable declaration using `let` is a statement" ) ;
2825
2825
return Err ( db) ;
2826
2826
} else if self . token . is_path_start ( ) {
2827
- let pth = self . parse_path ( PathStyle :: Expr ) ?;
2827
+ let path = self . parse_path ( PathStyle :: Expr ) ?;
2828
2828
2829
2829
// `!`, as an operator, is prefix, so we know this isn't that
2830
2830
if self . eat ( & token:: Not ) {
2831
2831
// MACRO INVOCATION expression
2832
2832
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 ) {
2838
2837
// This is a struct literal, unless we're prohibited
2839
2838
// 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) ;
2846
2843
}
2847
-
2848
- hi = pth. span ;
2849
- ex = ExprKind :: Path ( None , pth) ;
2850
2844
} else {
2851
2845
if !self . unclosed_delims . is_empty ( ) && self . check ( & token:: Semi ) {
2852
2846
// Don't complain about bare semicolons after unclosed braces
@@ -2881,10 +2875,8 @@ impl<'a> Parser<'a> {
2881
2875
}
2882
2876
}
2883
2877
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 )
2888
2880
}
2889
2881
2890
2882
fn parse_struct_expr ( & mut self , lo : Span , pth : ast:: Path , mut attrs : ThinVec < Attribute > )
@@ -4579,6 +4571,7 @@ impl<'a> Parser<'a> {
4579
4571
allow_range_pat : bool ,
4580
4572
expected : Option < & ' static str > ,
4581
4573
) -> PResult < ' a , P < Pat > > {
4574
+ maybe_recover_from_interpolated_ty_qpath ! ( self , true ) ;
4582
4575
maybe_whole ! ( self , NtPat , |x| x) ;
4583
4576
4584
4577
let lo = self . span ;
@@ -4754,7 +4747,7 @@ impl<'a> Parser<'a> {
4754
4747
}
4755
4748
}
4756
4749
4757
- let pat = Pat { node : pat, span : lo. to ( self . prev_span ) , id : ast:: DUMMY_NODE_ID } ;
4750
+ let pat = P ( Pat { node : pat, span : lo. to ( self . prev_span ) , id : ast:: DUMMY_NODE_ID } ) ;
4758
4751
let pat = self . maybe_recover_from_bad_qpath ( pat, true ) ?;
4759
4752
4760
4753
if !allow_range_pat {
@@ -4780,7 +4773,7 @@ impl<'a> Parser<'a> {
4780
4773
}
4781
4774
}
4782
4775
4783
- Ok ( P ( pat) )
4776
+ Ok ( pat)
4784
4777
}
4785
4778
4786
4779
/// Parses `ident` or `ident @ pat`.
@@ -5244,7 +5237,8 @@ impl<'a> Parser<'a> {
5244
5237
self . warn_missing_semicolon ( ) ;
5245
5238
StmtKind :: Mac ( P ( ( mac, style, attrs. into ( ) ) ) )
5246
5239
} else {
5247
- let e = self . mk_mac_expr ( lo. to ( hi) , mac. node , ThinVec :: new ( ) ) ;
5240
+ let e = self . mk_expr ( mac. span , ExprKind :: Mac ( mac) , ThinVec :: new ( ) ) ;
5241
+ let e = self . maybe_recover_from_bad_qpath ( e, true ) ?;
5248
5242
let e = self . parse_dot_or_call_expr_with ( e, lo, attrs. into ( ) ) ?;
5249
5243
let e = self . parse_assoc_expr_with ( 0 , LhsExpr :: AlreadyParsed ( e) ) ?;
5250
5244
StmtKind :: Expr ( e)
0 commit comments