@@ -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 > ,
@@ -121,9 +122,40 @@ impl<'a> TokenTreesReader<'a> {
121
122
// out instead of complaining about the unclosed delims.
122
123
let mut parser = crate :: stream_to_parser ( self . string_reader . sess , tts, None ) ;
123
124
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 ;
124
129
while parser. token != token:: Eof {
125
130
if let Err ( diff_err) = parser. err_diff_marker ( ) {
126
131
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
+ }
127
159
}
128
160
parser. bump ( ) ;
129
161
}
0 commit comments