Auto merge of #101362 - compiler-errors:unnecessary-let, r=cjgillot
Suggest removing unnecessary prefix let in patterns Helps with #101291, though I think `@estebank` probably wants this: > Finally, I think it'd be nice if we could detect that we don't know for sure and "just" swallow the rest of the expression (find the next ; accounting for nested braces) or the end of the item (easier). ... to be implemented before we close that issue out completely.
This commit is contained in:
commit
a594044533
@ -398,6 +398,30 @@ impl Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the token can appear at the start of an pattern.
|
||||||
|
///
|
||||||
|
/// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
|
||||||
|
pub fn can_begin_pattern(&self) -> bool {
|
||||||
|
match self.uninterpolate().kind {
|
||||||
|
Ident(name, is_raw) =>
|
||||||
|
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
||||||
|
| OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array
|
||||||
|
| Literal(..) // literal
|
||||||
|
| BinOp(Minus) // unary minus
|
||||||
|
| BinOp(And) // reference
|
||||||
|
| AndAnd // double reference
|
||||||
|
// DotDotDot is no longer supported
|
||||||
|
| DotDot | DotDotDot | DotDotEq // ranges
|
||||||
|
| Lt | BinOp(Shl) // associated path
|
||||||
|
| ModSep => true, // global path
|
||||||
|
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
|
||||||
|
NtPat(..) |
|
||||||
|
NtBlock(..) |
|
||||||
|
NtPath(..)),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token can appear at the start of a type.
|
/// Returns `true` if the token can appear at the start of a type.
|
||||||
pub fn can_begin_type(&self) -> bool {
|
pub fn can_begin_type(&self) -> bool {
|
||||||
match self.uninterpolate().kind {
|
match self.uninterpolate().kind {
|
||||||
|
@ -150,3 +150,6 @@ parser_dotdotdot = unexpected token: `...`
|
|||||||
|
|
||||||
parser_left_arrow_operator = unexpected token: `<-`
|
parser_left_arrow_operator = unexpected token: `<-`
|
||||||
.suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
|
.suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
|
||||||
|
|
||||||
|
parser_remove_let = expected pattern, found `let`
|
||||||
|
.suggestion = remove the unnecessary `let` keyword
|
||||||
|
@ -705,6 +705,14 @@ pub(crate) struct LeftArrowOperator {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(parser::remove_let)]
|
||||||
|
pub(crate) struct RemoveLet {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(applicability = "machine-applicable", code = "")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
// SnapshotParser is used to create a snapshot of the parser
|
// SnapshotParser is used to create a snapshot of the parser
|
||||||
// without causing duplicate errors being emitted when the `Parser`
|
// without causing duplicate errors being emitted when the `Parser`
|
||||||
// is dropped.
|
// is dropped.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
||||||
|
use crate::parser::diagnostics::RemoveLet;
|
||||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||||
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
@ -320,7 +321,13 @@ impl<'a> Parser<'a> {
|
|||||||
maybe_recover_from_interpolated_ty_qpath!(self, true);
|
maybe_recover_from_interpolated_ty_qpath!(self, true);
|
||||||
maybe_whole!(self, NtPat, |x| x);
|
maybe_whole!(self, NtPat, |x| x);
|
||||||
|
|
||||||
let lo = self.token.span;
|
let mut lo = self.token.span;
|
||||||
|
|
||||||
|
if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
|
||||||
|
self.bump();
|
||||||
|
self.sess.emit_err(RemoveLet { span: lo });
|
||||||
|
lo = self.token.span;
|
||||||
|
}
|
||||||
|
|
||||||
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
|
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
|
||||||
self.parse_pat_deref(expected)?
|
self.parse_pat_deref(expected)?
|
||||||
|
11
src/test/ui/parser/unnecessary-let.rs
Normal file
11
src/test/ui/parser/unnecessary-let.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fn main() {
|
||||||
|
for let x of [1, 2, 3] {}
|
||||||
|
//~^ ERROR expected pattern, found `let`
|
||||||
|
//~| ERROR missing `in` in `for` loop
|
||||||
|
|
||||||
|
match 1 {
|
||||||
|
let 1 => {}
|
||||||
|
//~^ ERROR expected pattern, found `let`
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
20
src/test/ui/parser/unnecessary-let.stderr
Normal file
20
src/test/ui/parser/unnecessary-let.stderr
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
error: expected pattern, found `let`
|
||||||
|
--> $DIR/unnecessary-let.rs:2:9
|
||||||
|
|
|
||||||
|
LL | for let x of [1, 2, 3] {}
|
||||||
|
| ^^^ help: remove the unnecessary `let` keyword
|
||||||
|
|
||||||
|
error: missing `in` in `for` loop
|
||||||
|
--> $DIR/unnecessary-let.rs:2:15
|
||||||
|
|
|
||||||
|
LL | for let x of [1, 2, 3] {}
|
||||||
|
| ^^ help: try using `in` here instead
|
||||||
|
|
||||||
|
error: expected pattern, found `let`
|
||||||
|
--> $DIR/unnecessary-let.rs:7:9
|
||||||
|
|
|
||||||
|
LL | let 1 => {}
|
||||||
|
| ^^^ help: remove the unnecessary `let` keyword
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user