Consider lint check attributes on match arms in match checks

This commit is contained in:
Ryo Yoshida 2023-05-18 23:45:48 +09:00
parent ddafe23401
commit 3a03587836
No known key found for this signature in database
GPG Key ID: E25698A930586171
3 changed files with 88 additions and 23 deletions

View File

@ -90,35 +90,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
match arm.guard {
Some(Guard::If(expr)) => {
self.with_let_source(LetSource::IfLetGuard, |this| {
this.visit_expr(&this.thir[expr])
});
self.with_lint_level(arm.lint_level, |this| {
match arm.guard {
Some(Guard::If(expr)) => {
this.with_let_source(LetSource::IfLetGuard, |this| {
this.visit_expr(&this.thir[expr])
});
}
Some(Guard::IfLet(ref pat, expr)) => {
this.with_let_source(LetSource::IfLetGuard, |this| {
this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
this.visit_pat(pat);
this.visit_expr(&this.thir[expr]);
});
}
None => {}
}
Some(Guard::IfLet(ref pat, expr)) => {
self.with_let_source(LetSource::IfLetGuard, |this| {
this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
this.visit_pat(pat);
this.visit_expr(&this.thir[expr]);
});
}
None => {}
}
self.visit_pat(&arm.pattern);
self.visit_expr(&self.thir[arm.body]);
this.visit_pat(&arm.pattern);
this.visit_expr(&self.thir[arm.body]);
});
}
#[instrument(level = "trace", skip(self))]
fn visit_expr(&mut self, ex: &Expr<'tcx>) {
match ex.kind {
ExprKind::Scope { value, lint_level, .. } => {
let old_lint_level = self.lint_level;
if let LintLevel::Explicit(hir_id) = lint_level {
self.lint_level = hir_id;
}
self.visit_expr(&self.thir[value]);
self.lint_level = old_lint_level;
self.with_lint_level(lint_level, |this| {
this.visit_expr(&this.thir[value]);
});
return;
}
ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
@ -190,6 +189,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
self.let_source = old_let_source;
}
fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
if let LintLevel::Explicit(hir_id) = new_lint_level {
let old_lint_level = self.lint_level;
self.lint_level = hir_id;
f(self);
self.lint_level = old_lint_level;
} else {
f(self);
}
}
fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
check_for_bindings_named_same_as_variants(self, pat, rf);
@ -236,7 +246,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
let arm = &self.thir.arms[arm];
self.check_patterns(&arm.pattern, Refutable);
self.with_lint_level(arm.lint_level, |this| {
this.check_patterns(&arm.pattern, Refutable);
});
}
let tarms: Vec<_> = arms

View File

@ -0,0 +1,24 @@
#![feature(if_let_guard)]
#![allow(unused, non_snake_case)]
enum E {
A,
}
#[allow(bindings_with_variant_name, irrefutable_let_patterns)]
fn foo() {
match E::A {
#[deny(bindings_with_variant_name)]
A => {}
//~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E`
}
match &E::A {
#[deny(irrefutable_let_patterns)]
a if let b = a => {}
//~^ ERROR irrefutable `if let` guard pattern
_ => {}
}
}
fn main() { }

View File

@ -0,0 +1,29 @@
error[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
--> $DIR/lint-match-arms-2.rs:12:9
|
LL | A => {}
| ^ help: to match on the variant, qualify the path: `E::A`
|
note: the lint level is defined here
--> $DIR/lint-match-arms-2.rs:11:16
|
LL | #[deny(bindings_with_variant_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: irrefutable `if let` guard pattern
--> $DIR/lint-match-arms-2.rs:18:18
|
LL | a if let b = a => {}
| ^
|
= note: this pattern will always match, so the guard is useless
= help: consider removing the guard and adding a `let` inside the match arm
note: the lint level is defined here
--> $DIR/lint-match-arms-2.rs:17:16
|
LL | #[deny(irrefutable_let_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0170`.