Only emit lint on refutable patterns.

This commit is contained in:
Camille GILLOT 2023-04-03 16:13:06 +00:00
parent 03fbb3db1e
commit 03a6ef67fe
2 changed files with 10 additions and 8 deletions

View File

@ -199,12 +199,13 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern))
}
fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> {
fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> {
MatchCheckCtxt {
tcx: self.tcx,
param_env: self.param_env,
module: self.tcx.parent_module(hir_id).to_def_id(),
pattern_arena: &self.pattern_arena,
refutable,
}
}
@ -214,7 +215,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
return;
}
self.check_patterns(pat, Refutable);
let mut cx = self.new_cx(self.lint_level);
let mut cx = self.new_cx(self.lint_level, true);
let tpat = self.lower_pattern(&mut cx, pat);
self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span);
}
@ -226,7 +227,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
source: hir::MatchSource,
expr_span: Span,
) {
let mut cx = self.new_cx(self.lint_level);
let mut cx = self.new_cx(self.lint_level, true);
for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
@ -328,7 +329,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
debug!(?expr, ?local_lint_level, "after scopes");
match expr.kind {
ExprKind::Let { box ref pat, expr: _ } => {
let mut ncx = self.new_cx(local_lint_level);
let mut ncx = self.new_cx(local_lint_level, true);
let tpat = self.lower_pattern(&mut ncx, pat);
let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat);
Some((expr.span, refutable))
@ -409,7 +410,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
let mut cx = self.new_cx(self.lint_level);
let mut cx = self.new_cx(self.lint_level, false);
let pattern = self.lower_pattern(&mut cx, pat);
let pattern_ty = pattern.ty();

View File

@ -300,7 +300,6 @@ use rustc_arena::TypedArena;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_hir::Node;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_span::{Span, DUMMY_SP};
@ -319,6 +318,8 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> {
pub(crate) module: DefId,
pub(crate) param_env: ty::ParamEnv<'tcx>,
pub(crate) pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
/// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns.
pub(crate) refutable: bool,
}
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
@ -860,6 +861,8 @@ fn is_useful<'p, 'tcx>(
// that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
// To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
if is_non_exhaustive_and_wild
// Only emit a lint on refutable patterns.
&& cx.refutable
// We check that the match has a wildcard pattern and that wildcard is useful,
// meaning there are variants that are covered by the wildcard. Without the check
// for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
@ -868,8 +871,6 @@ fn is_useful<'p, 'tcx>(
&ctor,
Constructor::Missing { nonexhaustive_enum_missing_real_variants: true }
)
// We don't want to lint patterns which are function arguments or locals
&& !matches!(cx.tcx.hir().find_parent(hir_id), Some(Node::Param(_)|Node::Local(_)))
{
let patterns = {
let mut split_wildcard = SplitWildcard::new(pcx);