@@ -5,7 +5,8 @@ use super::{StringReader, UnmatchedDelim};
5
5
use rustc_ast:: token:: { self , Delimiter , Token } ;
6
6
use rustc_ast:: tokenstream:: { DelimSpan , Spacing , TokenStream , TokenTree } ;
7
7
use rustc_ast_pretty:: pprust:: token_to_string;
8
- use rustc_errors:: PErr ;
8
+ use rustc_errors:: { Applicability , PErr } ;
9
+ use rustc_span:: symbol:: kw;
9
10
10
11
pub ( super ) struct TokenTreesReader < ' a > {
11
12
string_reader : StringReader < ' a > ,
@@ -116,24 +117,8 @@ impl<'a> TokenTreesReader<'a> {
116
117
// We stop at any delimiter so we can try to recover if the user
117
118
// uses an incorrect delimiter.
118
119
let ( tts, res) = self . parse_token_trees ( /* is_delimited */ true ) ;
119
- if let Err ( mut errs) = res {
120
- // If there are unclosed delims, see if there are diff markers and if so, point them
121
- // out instead of complaining about the unclosed delims.
122
- let mut parser = crate :: stream_to_parser ( self . string_reader . sess , tts, None ) ;
123
- let mut diff_errs = vec ! [ ] ;
124
- while parser. token != token:: Eof {
125
- if let Err ( diff_err) = parser. err_diff_marker ( ) {
126
- diff_errs. push ( diff_err) ;
127
- }
128
- parser. bump ( ) ;
129
- }
130
- if !diff_errs. is_empty ( ) {
131
- errs. iter_mut ( ) . for_each ( |err| {
132
- err. delay_as_bug ( ) ;
133
- } ) ;
134
- return Err ( diff_errs) ;
135
- }
136
- return Err ( errs) ;
120
+ if let Err ( errs) = res {
121
+ return Err ( self . unclosed_delim_err ( tts, errs) ) ;
137
122
}
138
123
139
124
// Expand to cover the entire delimited token tree
@@ -220,6 +205,62 @@ impl<'a> TokenTreesReader<'a> {
220
205
Ok ( TokenTree :: Delimited ( delim_span, open_delim, tts) )
221
206
}
222
207
208
+ fn unclosed_delim_err ( & mut self , tts : TokenStream , mut errs : Vec < PErr < ' a > > ) -> Vec < PErr < ' a > > {
209
+ // If there are unclosed delims, see if there are diff markers and if so, point them
210
+ // out instead of complaining about the unclosed delims.
211
+ let mut parser = crate :: stream_to_parser ( self . string_reader . sess , tts, None ) ;
212
+ let mut diff_errs = vec ! [ ] ;
213
+ // Suggest removing a `{` we think appears in an `if`/`while` condition
214
+ // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, but
215
+ // we have no way of tracking this in the lexer itself, so we piggyback on the parser
216
+ let mut in_cond = false ;
217
+ while parser. token != token:: Eof {
218
+ if let Err ( diff_err) = parser. err_diff_marker ( ) {
219
+ diff_errs. push ( diff_err) ;
220
+ } else if parser. is_keyword_ahead ( 0 , & [ kw:: If , kw:: While ] ) {
221
+ in_cond = true ;
222
+ } else if matches ! (
223
+ parser. token. kind,
224
+ token:: CloseDelim ( Delimiter :: Brace ) | token:: FatArrow
225
+ ) {
226
+ // end of the `if`/`while` body, or the end of a `match` guard
227
+ in_cond = false ;
228
+ } else if in_cond && parser. token == token:: OpenDelim ( Delimiter :: Brace ) {
229
+ // Store the `&&` and `let` to use their spans later when creating the diagnostic
230
+ let maybe_andand = parser. look_ahead ( 1 , |t| t. clone ( ) ) ;
231
+ let maybe_let = parser. look_ahead ( 2 , |t| t. clone ( ) ) ;
232
+ if maybe_andand == token:: OpenDelim ( Delimiter :: Brace ) {
233
+ // This might be the beginning of the `if`/`while` body (i.e., the end of the condition)
234
+ in_cond = false ;
235
+ } else if maybe_andand == token:: AndAnd && maybe_let. is_keyword ( kw:: Let ) {
236
+ let mut err = parser. struct_span_err (
237
+ parser. token . span ,
238
+ "found a `{` in the middle of a let-chain" ,
239
+ ) ;
240
+ err. span_suggestion (
241
+ parser. token . span ,
242
+ "consider removing this brace to parse the `let` as part of the same chain" ,
243
+ "" ,
244
+ Applicability :: MachineApplicable ,
245
+ ) ;
246
+ err. span_label (
247
+ maybe_andand. span . to ( maybe_let. span ) ,
248
+ "you might have meant to continue the let-chain here" ,
249
+ ) ;
250
+ errs. push ( err) ;
251
+ }
252
+ }
253
+ parser. bump ( ) ;
254
+ }
255
+ if !diff_errs. is_empty ( ) {
256
+ errs. iter_mut ( ) . for_each ( |err| {
257
+ err. delay_as_bug ( ) ;
258
+ } ) ;
259
+ return diff_errs;
260
+ }
261
+ return errs;
262
+ }
263
+
223
264
fn close_delim_err ( & mut self , delim : Delimiter ) -> PErr < ' a > {
224
265
// An unexpected closing delimiter (i.e., there is no
225
266
// matching opening delimiter).
0 commit comments