1
Fork 0

Catch stray { in let-chains

This commit is contained in:
sjwang05 2023-11-09 18:46:45 -08:00
parent 4c8862b263
commit 0094238157
No known key found for this signature in database
GPG key ID: AB262FD6FFBFCFFE
3 changed files with 103 additions and 1 deletions

View file

@ -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();
}