@@ -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 > ,
@@ -121,9 +122,40 @@ impl<'a> TokenTreesReader<'a> {
121122 // out instead of complaining about the unclosed delims.
122123 let mut parser = crate :: stream_to_parser ( self . string_reader . sess , tts, None ) ;
123124 let mut diff_errs = vec ! [ ] ;
125+ // Suggest removing a `{` we think appears in an `if`/`while` condition
126+ // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, but
127+ // we have no way of tracking this in the lexer itself, so we piggyback on the parser
128+ let mut in_cond = false ;
124129 while parser. token != token:: Eof {
125130 if let Err ( diff_err) = parser. err_diff_marker ( ) {
126131 diff_errs. push ( diff_err) ;
132+ } else if parser. token . is_keyword ( kw:: If ) {
133+ in_cond = true ;
134+ } else if parser. token == token:: CloseDelim ( Delimiter :: Brace ) {
135+ in_cond = false ;
136+ } else if in_cond && parser. token == token:: OpenDelim ( Delimiter :: Brace ) {
137+ // Store the `&&` and `let` to use their spans later when creating the diagnostic
138+ let maybe_andand = parser. look_ahead ( 1 , |t| t. clone ( ) ) ;
139+ let maybe_let = parser. look_ahead ( 2 , |t| t. clone ( ) ) ;
140+ if maybe_andand == token:: OpenDelim ( Delimiter :: Brace ) {
141+ // This might be the beginning of the `if`/`while` body (i.e., the end of the condition)
142+ in_cond = false ;
143+ } else if maybe_andand == token:: AndAnd && maybe_let. is_keyword ( kw:: Let ) {
144+ let mut err = parser. struct_span_err (
145+ parser. token . span ,
146+ "found a `{` in the middle of a let-chain" ,
147+ ) ;
148+ err. span_suggestion (
149+ parser. token . span ,
150+ "consider removing this brace to parse the `let` as part of the same chain" ,
151+ "" , Applicability :: MachineApplicable
152+ ) ;
153+ err. span_note (
154+ maybe_andand. span . to ( maybe_let. span ) ,
155+ "you might have meant to continue the let-chain here" ,
156+ ) ;
157+ errs. push ( err) ;
158+ }
127159 }
128160 parser. bump ( ) ;
129161 }
0 commit comments