Skip to content

Commit

Permalink
Rollup merge of #101362 - compiler-errors:unnecessary-let, r=cjgillot
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matthiaskrgr authored Sep 5, 2022
2 parents 96704a6 + 91674cc commit 42770d1
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 1 deletion.
24 changes: 24 additions & 0 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
pub fn can_begin_type(&self) -> bool {
match self.uninterpolate().kind {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/parser.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,6 @@ parser_dotdotdot = 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 `-`
parser_remove_let = expected pattern, found `let`
.suggestion = remove the unnecessary `let` keyword
8 changes: 8 additions & 0 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,14 @@ pub(crate) struct LeftArrowOperator {
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
// without causing duplicate errors being emitted when the `Parser`
// is dropped.
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
use crate::parser::diagnostics::RemoveLet;
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
Expand Down Expand Up @@ -320,7 +321,13 @@ impl<'a> Parser<'a> {
maybe_recover_from_interpolated_ty_qpath!(self, true);
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 {
self.parse_pat_deref(expected)?
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/parser/unnecessary-let.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions src/test/ui/parser/unnecessary-let.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 42770d1

Please sign in to comment.