Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check pattern refutability on THIR #108504

Merged
merged 13 commits into from
Apr 6, 2023
Prev Previous commit
Next Next commit
Only emit lint on refutable patterns.
cjgillot committed Apr 3, 2023
commit 03a6ef67fe72c58d976c3e83ffab2296179ae8a4
11 changes: 6 additions & 5 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
@@ -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();
7 changes: 4 additions & 3 deletions compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
Original file line number Diff line number Diff line change
@@ -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);