diff options
| author | sjwang05 <63834813+sjwang05@users.noreply.github.com> | 2023-11-09 18:46:45 -0800 |
|---|---|---|
| committer | sjwang05 <63834813+sjwang05@users.noreply.github.com> | 2023-11-09 18:47:49 -0800 |
| commit | 00942381575bc6c081835dbb38f68ce9603c032f (patch) | |
| tree | 47d2f01e2c7bc45534d65d5a93c051edc97c74e9 /compiler/rustc_parse | |
| parent | 4c8862b26330ae7a60b3ae0023fab86bcc48613a (diff) | |
| download | rust-00942381575bc6c081835dbb38f68ce9603c032f.tar.gz rust-00942381575bc6c081835dbb38f68ce9603c032f.zip | |
Catch stray { in let-chains
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/src/lexer/tokentrees.rs | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 31d91fe80bd..7aa4ac7c4cb 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -5,7 +5,8 @@ use super::{StringReader, UnmatchedDelim}; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; -use rustc_errors::PErr; +use rustc_errors::{Applicability, PErr}; +use rustc_span::symbol::kw; pub(super) struct TokenTreesReader<'a> { string_reader: StringReader<'a>, @@ -121,9 +122,40 @@ impl<'a> TokenTreesReader<'a> { // out instead of complaining about the unclosed delims. let mut parser = crate::stream_to_parser(self.string_reader.sess, tts, None); let mut diff_errs = vec![]; + // Suggest removing a `{` we think appears in an `if`/`while` condition + // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, but + // we have no way of tracking this in the lexer itself, so we piggyback on the parser + let mut in_cond = false; while parser.token != token::Eof { if let Err(diff_err) = parser.err_diff_marker() { diff_errs.push(diff_err); + } else if parser.token.is_keyword(kw::If) { + in_cond = true; + } else if parser.token == token::CloseDelim(Delimiter::Brace) { + in_cond = false; + } else if in_cond && parser.token == token::OpenDelim(Delimiter::Brace) { + // Store the `&&` and `let` to use their spans later when creating the diagnostic + let maybe_andand = parser.look_ahead(1, |t| t.clone()); + let maybe_let = parser.look_ahead(2, |t| t.clone()); + if maybe_andand == token::OpenDelim(Delimiter::Brace) { + // This might be the beginning of the `if`/`while` body (i.e., the end of the condition) + in_cond = false; + } else if maybe_andand == token::AndAnd && maybe_let.is_keyword(kw::Let) { + let mut err = parser.struct_span_err( + parser.token.span, + "found a `{` in the middle of a let-chain", + ); + err.span_suggestion( + parser.token.span, + "consider removing this brace to parse the `let` as part of the same chain", + "", Applicability::MachineApplicable + ); + err.span_note( + maybe_andand.span.to(maybe_let.span), + "you might have meant to continue the let-chain here", + ); + errs.push(err); + } } parser.bump(); } |
