Catch stray { in let-chains
This commit is contained in:
parent
4c8862b263
commit
0094238157
@ -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();
|
||||
}
|
||||
|
28
tests/ui/parser/brace-in-let-chain.rs
Normal file
28
tests/ui/parser/brace-in-let-chain.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// issue #117766
|
||||
|
||||
#![feature(let_chains)]
|
||||
fn main() {
|
||||
if let () = ()
|
||||
&& let () = () { //~ERROR: found a `{` in the middle of a let-chain
|
||||
&& let () = ()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
{
|
||||
&& let () = ()
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
if false {}
|
||||
{
|
||||
&& let () = ()
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
if false {
|
||||
{
|
||||
&& let () = ()
|
||||
}
|
||||
} //~ERROR: this file contains an unclosed delimiter
|
42
tests/ui/parser/brace-in-let-chain.stderr
Normal file
42
tests/ui/parser/brace-in-let-chain.stderr
Normal file
@ -0,0 +1,42 @@
|
||||
error: this file contains an unclosed delimiter
|
||||
--> $DIR/brace-in-let-chain.rs:28:54
|
||||
|
|
||||
LL | fn main() {
|
||||
| - unclosed delimiter
|
||||
...
|
||||
LL | fn foo() {
|
||||
| - unclosed delimiter
|
||||
...
|
||||
LL | fn bar() {
|
||||
| - unclosed delimiter
|
||||
...
|
||||
LL | fn baz() {
|
||||
| - unclosed delimiter
|
||||
LL | if false {
|
||||
LL | {
|
||||
| - this delimiter might not be properly closed...
|
||||
LL | && let () = ()
|
||||
LL | }
|
||||
| - ...as it matches this but it has different indentation
|
||||
LL | }
|
||||
| ^
|
||||
|
||||
error: found a `{` in the middle of a let-chain
|
||||
--> $DIR/brace-in-let-chain.rs:6:24
|
||||
|
|
||||
LL | && let () = () {
|
||||
| ^
|
||||
|
|
||||
note: you might have meant to continue the let-chain here
|
||||
--> $DIR/brace-in-let-chain.rs:7:9
|
||||
|
|
||||
LL | && let () = ()
|
||||
| ^^^^^^
|
||||
help: consider removing this brace to parse the `let` as part of the same chain
|
||||
|
|
||||
LL - && let () = () {
|
||||
LL + && let () = ()
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user