@@ -5,7 +5,8 @@ use super::{StringReader, UnmatchedDelim};
55use rustc_ast:: token:: { self , Delimiter , Token } ;
66use rustc_ast:: tokenstream:: { DelimSpan , Spacing , TokenStream , TokenTree } ;
77use rustc_ast_pretty:: pprust:: token_to_string;
8- use rustc_errors:: PErr ;
8+ use rustc_errors:: { Applicability , PErr } ;
9+ use rustc_span:: symbol:: kw;
910
1011pub ( super ) struct TokenTreesReader < ' a > {
1112 string_reader : StringReader < ' a > ,
@@ -116,24 +117,8 @@ impl<'a> TokenTreesReader<'a> {
116117 // We stop at any delimiter so we can try to recover if the user
117118 // uses an incorrect delimiter.
118119 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) ) ;
137122 }
138123
139124 // Expand to cover the entire delimited token tree
@@ -220,6 +205,62 @@ impl<'a> TokenTreesReader<'a> {
220205 Ok ( TokenTree :: Delimited ( delim_span, open_delim, tts) )
221206 }
222207
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+
223264 fn close_delim_err ( & mut self , delim : Delimiter ) -> PErr < ' a > {
224265 // An unexpected closing delimiter (i.e., there is no
225266 // matching opening delimiter).
0 commit comments