Consider lint check attributes on match arms in match checks
This commit is contained in:
parent
ddafe23401
commit
3a03587836
3 changed files with 88 additions and 23 deletions
|
@ -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
|
||||
|
|
24
tests/ui/lint/lint-match-arms-2.rs
Normal file
24
tests/ui/lint/lint-match-arms-2.rs
Normal 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() { }
|
29
tests/ui/lint/lint-match-arms-2.stderr
Normal file
29
tests/ui/lint/lint-match-arms-2.stderr
Normal 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`.
|
Loading…
Add table
Reference in a new issue