summary refs log tree commit diff
path: root/compiler/rustc_pattern_analysis
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2023-12-15 16:53:29 +0100
committerNadrieril <nadrieril+git@gmail.com>2023-12-15 16:58:38 +0100
commit4bcf66f875d77d0d5897c5b0b9d6bbd985d03a31 (patch)
tree34cb871f1251205e9f51505a76de13f02859d9b3 /compiler/rustc_pattern_analysis
parent60ea14bfaab32d2d1d5f956acfd08d72a2a79e1c (diff)
downloadrust-4bcf66f875d77d0d5897c5b0b9d6bbd985d03a31.tar.gz
rust-4bcf66f875d77d0d5897c5b0b9d6bbd985d03a31.zip
Introduce `MatchCtxt`
Diffstat (limited to 'compiler/rustc_pattern_analysis')
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs9
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs46
-rw-r--r--compiler/rustc_pattern_analysis/src/lints.rs56
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs6
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs1
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs52
6 files changed, 93 insertions, 77 deletions
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index ec1ddd56b1c..99044e00aeb 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -718,7 +718,7 @@ impl<Cx: MatchCx> Constructor<Cx> {
     /// The number of fields for this constructor. This must be kept in sync with
     /// `Fields::wildcards`.
     pub(crate) fn arity(&self, pcx: &PlaceCtxt<'_, '_, Cx>) -> usize {
-        pcx.cx.ctor_arity(self, pcx.ty)
+        pcx.ctor_arity(self)
     }
 
     /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
@@ -729,7 +729,8 @@ impl<Cx: MatchCx> Constructor<Cx> {
     pub(crate) fn is_covered_by<'p>(&self, pcx: &PlaceCtxt<'_, 'p, Cx>, other: &Self) -> bool {
         match (self, other) {
             (Wildcard, _) => pcx
-                .cx
+                .mcx
+                .tycx
                 .bug(format_args!("Constructor splitting should not have returned `Wildcard`")),
             // Wildcards cover anything
             (_, Wildcard) => true,
@@ -771,7 +772,7 @@ impl<Cx: MatchCx> Constructor<Cx> {
             (Opaque(self_id), Opaque(other_id)) => self_id == other_id,
             (Opaque(..), _) | (_, Opaque(..)) => false,
 
-            _ => pcx.cx.bug(format_args!(
+            _ => pcx.mcx.tycx.bug(format_args!(
                 "trying to compare incompatible constructors {self:?} and {other:?}"
             )),
         }
@@ -1007,7 +1008,7 @@ impl<Cx: MatchCx> ConstructorSet<Cx> {
         // We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
         // In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
         // types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
-        if !pcx.cx.is_exhaustive_patterns_feature_on()
+        if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on()
             && !(pcx.is_scrutinee && matches!(self, Self::NoConstructors))
         {
             // Treat all missing constructors as nonempty.
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 12d2e0fc18b..44bc09d07fe 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -36,6 +36,19 @@ use crate::rustc::RustcMatchCheckCtxt;
 #[cfg(feature = "rustc")]
 use crate::usefulness::{compute_match_usefulness, ValidityConstraint};
 
+// It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
+// we use another feature instead. The crate won't compile if one of these isn't enabled.
+#[cfg(feature = "rustc")]
+pub(crate) use rustc_arena::TypedArena;
+#[cfg(feature = "stable")]
+pub(crate) use typed_arena::Arena as TypedArena;
+
+pub trait Captures<'a> {}
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+/// Context that provides type information about constructors.
+///
+/// Most of the crate is parameterized on a type that implements this trait.
 pub trait MatchCx: Sized + Clone + fmt::Debug {
     /// The type of a pattern.
     type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
@@ -71,10 +84,20 @@ pub trait MatchCx: Sized + Clone + fmt::Debug {
     fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
 }
 
+/// Context that provides information global to a match.
+#[derive(Clone)]
+pub struct MatchCtxt<'a, 'p, Cx: MatchCx> {
+    /// The context for type information.
+    pub tycx: &'a Cx,
+    /// An arena to store the wildcards we produce during analysis.
+    pub wildcard_arena: &'a TypedArena<DeconstructedPat<'p, Cx>>,
+}
+
+impl<'a, 'p, Cx: MatchCx> Copy for MatchCtxt<'a, 'p, Cx> {}
+
 /// The arm of a match expression.
 #[derive(Clone, Debug)]
 pub struct MatchArm<'p, Cx: MatchCx> {
-    /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
     pub pat: &'p DeconstructedPat<'p, Cx>,
     pub has_guard: bool,
     pub arm_data: Cx::ArmData,
@@ -82,31 +105,30 @@ pub struct MatchArm<'p, Cx: MatchCx> {
 
 impl<'p, Cx: MatchCx> Copy for MatchArm<'p, Cx> {}
 
-pub trait Captures<'a> {}
-impl<'a, T: ?Sized> Captures<'a> for T {}
-
 /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
 /// useful, and runs some lints.
 #[cfg(feature = "rustc")]
 pub fn analyze_match<'p, 'tcx>(
-    cx: &RustcMatchCheckCtxt<'p, 'tcx>,
+    tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
     arms: &[rustc::MatchArm<'p, 'tcx>],
     scrut_ty: Ty<'tcx>,
 ) -> rustc::UsefulnessReport<'p, 'tcx> {
     // Arena to store the extra wildcards we construct during analysis.
-    let wildcard_arena = cx.pattern_arena;
-    let pat_column = PatternColumn::new(arms);
+    let wildcard_arena = tycx.pattern_arena;
+    let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
+    let cx = MatchCtxt { tycx, wildcard_arena };
+
+    let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
 
-    let scrut_validity = ValidityConstraint::from_bool(cx.known_valid_scrutinee);
-    let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity, wildcard_arena);
+    let pat_column = PatternColumn::new(arms);
 
     // Lint on ranges that overlap on their endpoints, which is likely a mistake.
-    lint_overlapping_range_endpoints(cx, &pat_column, wildcard_arena);
+    lint_overlapping_range_endpoints(cx, &pat_column);
 
     // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
     // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
-    if cx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
-        lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty, wildcard_arena)
+    if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
+        lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
     }
 
     report
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index 2d4b06669b5..f1287b1b4d2 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -1,4 +1,3 @@
-use rustc_arena::TypedArena;
 use smallvec::SmallVec;
 
 use rustc_data_structures::captures::Captures;
@@ -13,8 +12,8 @@ use crate::errors::{
     OverlappingRangeEndpoints, Uncovered,
 };
 use crate::rustc::{
-    Constructor, DeconstructedPat, MatchArm, PlaceCtxt, RustcMatchCheckCtxt, SplitConstructorSet,
-    WitnessPat,
+    Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RustcMatchCheckCtxt,
+    SplitConstructorSet, WitnessPat,
 };
 use crate::MatchCx;
 
@@ -70,7 +69,7 @@ impl<'a, 'p, 'tcx> PatternColumn<'a, 'p, 'tcx> {
     /// Do constructor splitting on the constructors of the column.
     fn analyze_ctors(&self, pcx: &PlaceCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'p, 'tcx> {
         let column_ctors = self.patterns.iter().map(|p| p.ctor());
-        pcx.cx.ctors_for_ty(pcx.ty).split(pcx, column_ctors)
+        pcx.ctors_for_ty().split(pcx, column_ctors)
     }
 
     fn iter<'b>(&'b self) -> impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>> + Captures<'b> {
@@ -121,16 +120,15 @@ impl<'a, 'p, 'tcx> PatternColumn<'a, 'p, 'tcx> {
 
 /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
 /// in a given column.
-#[instrument(level = "debug", skip(cx, wildcard_arena), ret)]
+#[instrument(level = "debug", skip(cx), ret)]
 fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
-    cx: &RustcMatchCheckCtxt<'p, 'tcx>,
+    cx: MatchCtxt<'a, 'p, 'tcx>,
     column: &PatternColumn<'a, 'p, 'tcx>,
-    wildcard_arena: &TypedArena<DeconstructedPat<'p, 'tcx>>,
 ) -> Vec<WitnessPat<'p, 'tcx>> {
     let Some(ty) = column.head_ty() else {
         return Vec::new();
     };
-    let pcx = &PlaceCtxt::new_dummy(cx, ty, wildcard_arena);
+    let pcx = &PlaceCtxt::new_dummy(cx, ty);
 
     let set = column.analyze_ctors(pcx);
     if set.present.is_empty() {
@@ -141,7 +139,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
     }
 
     let mut witnesses = Vec::new();
-    if cx.is_foreign_non_exhaustive_enum(ty) {
+    if cx.tycx.is_foreign_non_exhaustive_enum(ty) {
         witnesses.extend(
             set.missing
                 .into_iter()
@@ -157,7 +155,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
         let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
         for (i, col_i) in specialized_columns.iter().enumerate() {
             // Compute witnesses for each column.
-            let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i, wildcard_arena);
+            let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i);
             // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
             // adding enough wildcards to match `arity`.
             for wit in wits_for_col_i {
@@ -171,29 +169,29 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
 }
 
 pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
-    cx: &RustcMatchCheckCtxt<'p, 'tcx>,
+    cx: MatchCtxt<'a, 'p, 'tcx>,
     arms: &[MatchArm<'p, 'tcx>],
     pat_column: &PatternColumn<'a, 'p, 'tcx>,
     scrut_ty: Ty<'tcx>,
-    wildcard_arena: &TypedArena<DeconstructedPat<'p, 'tcx>>,
 ) {
+    let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
     if !matches!(
-        cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, cx.match_lint_level).0,
+        rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
         rustc_session::lint::Level::Allow
     ) {
-        let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column, wildcard_arena);
+        let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column);
         if !witnesses.is_empty() {
             // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
             // is not exhaustive enough.
             //
             // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
-            cx.tcx.emit_spanned_lint(
+            rcx.tcx.emit_spanned_lint(
                 NON_EXHAUSTIVE_OMITTED_PATTERNS,
-                cx.match_lint_level,
-                cx.scrut_span,
+                rcx.match_lint_level,
+                rcx.scrut_span,
                 NonExhaustiveOmittedPattern {
                     scrut_ty,
-                    uncovered: Uncovered::new(cx.scrut_span, cx, witnesses),
+                    uncovered: Uncovered::new(rcx.scrut_span, rcx, witnesses),
                 },
             );
         }
@@ -203,17 +201,17 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
         // usage of the lint.
         for arm in arms {
             let (lint_level, lint_level_source) =
-                cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.arm_data);
+                rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.arm_data);
             if !matches!(lint_level, rustc_session::lint::Level::Allow) {
                 let decorator = NonExhaustiveOmittedPatternLintOnArm {
                     lint_span: lint_level_source.span(),
-                    suggest_lint_on_match: cx.whole_match_span.map(|span| span.shrink_to_lo()),
+                    suggest_lint_on_match: rcx.whole_match_span.map(|span| span.shrink_to_lo()),
                     lint_level: lint_level.as_str(),
                     lint_name: "non_exhaustive_omitted_patterns",
                 };
 
                 use rustc_errors::DecorateLint;
-                let mut err = cx.tcx.sess.struct_span_warn(*arm.pat.data(), "");
+                let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data(), "");
                 err.set_primary_message(decorator.msg());
                 decorator.decorate_lint(&mut err);
                 err.emit();
@@ -223,30 +221,30 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
 }
 
 /// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
-#[instrument(level = "debug", skip(cx, wildcard_arena))]
+#[instrument(level = "debug", skip(cx))]
 pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
-    cx: &RustcMatchCheckCtxt<'p, 'tcx>,
+    cx: MatchCtxt<'a, 'p, 'tcx>,
     column: &PatternColumn<'a, 'p, 'tcx>,
-    wildcard_arena: &TypedArena<DeconstructedPat<'p, 'tcx>>,
 ) {
     let Some(ty) = column.head_ty() else {
         return;
     };
-    let pcx = &PlaceCtxt::new_dummy(cx, ty, wildcard_arena);
+    let pcx = &PlaceCtxt::new_dummy(cx, ty);
+    let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
 
     let set = column.analyze_ctors(pcx);
 
     if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
         let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
-            let overlap_as_pat = cx.hoist_pat_range(overlap, ty);
+            let overlap_as_pat = rcx.hoist_pat_range(overlap, ty);
             let overlaps: Vec<_> = overlapped_spans
                 .iter()
                 .copied()
                 .map(|span| Overlap { range: overlap_as_pat.clone(), span })
                 .collect();
-            cx.tcx.emit_spanned_lint(
+            rcx.tcx.emit_spanned_lint(
                 lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
-                cx.match_lint_level,
+                rcx.match_lint_level,
                 this_span,
                 OverlappingRangeEndpoints { overlap: overlaps, range: this_span },
             );
@@ -291,7 +289,7 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
         // Recurse into the fields.
         for ctor in set.present {
             for col in column.specialize(pcx, &ctor) {
-                lint_overlapping_range_endpoints(cx, &col, wildcard_arena);
+                lint_overlapping_range_endpoints(cx, &col);
             }
         }
     }
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 4ddd5eb630a..defe95d3393 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -81,10 +81,10 @@ impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
         other_ctor: &Constructor<Cx>,
     ) -> SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]> {
         let wildcard_sub_tys = || {
-            let tys = pcx.cx.ctor_sub_tys(other_ctor, pcx.ty);
+            let tys = pcx.ctor_sub_tys(other_ctor);
             tys.iter()
                 .map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default()))
-                .map(|pat| pcx.wildcard_arena.alloc(pat) as &_)
+                .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
                 .collect()
         };
         match (&self.ctor, other_ctor) {
@@ -179,7 +179,7 @@ impl<Cx: MatchCx> WitnessPat<Cx> {
     /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
     /// `Some(_)`.
     pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, '_, Cx>, ctor: Constructor<Cx>) -> Self {
-        let field_tys = pcx.cx.ctor_sub_tys(&ctor, pcx.ty);
+        let field_tys = pcx.ctor_sub_tys(&ctor);
         let fields = field_tys.iter().map(|ty| Self::wildcard(*ty)).collect();
         Self::new(ctor, fields, pcx.ty)
     }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d9b8b3a39c0..e5d43ff09a1 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -31,6 +31,7 @@ pub type ConstructorSet<'p, 'tcx> =
 pub type DeconstructedPat<'p, 'tcx> =
     crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type MatchCtxt<'a, 'p, 'tcx> = crate::MatchCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub(crate) type PlaceCtxt<'a, 'p, 'tcx> =
     crate::usefulness::PlaceCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub(crate) type SplitConstructorSet<'p, 'tcx> =
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 9742507fef2..f9f6c7c637d 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -555,16 +555,9 @@
 use smallvec::{smallvec, SmallVec};
 use std::fmt;
 
-// It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
-// we use another feature instead. The crate won't compile if one of these isn't enabled.
-#[cfg(feature = "rustc")]
-use rustc_arena::TypedArena;
-#[cfg(feature = "stable")]
-use typed_arena::Arena as TypedArena;
-
 use crate::constructor::{Constructor, ConstructorSet};
 use crate::pat::{DeconstructedPat, WitnessPat};
-use crate::{Captures, MatchArm, MatchCx};
+use crate::{Captures, MatchArm, MatchCtxt, MatchCx, TypedArena};
 
 use self::ValidityConstraint::*;
 
@@ -578,9 +571,7 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
 /// Context that provides information local to a place under investigation.
 #[derive(Clone)]
 pub(crate) struct PlaceCtxt<'a, 'p, Cx: MatchCx> {
-    pub(crate) cx: &'a Cx,
-    /// An arena to store the wildcards we produce during analysis.
-    pub(crate) wildcard_arena: &'a TypedArena<DeconstructedPat<'p, Cx>>,
+    pub(crate) mcx: MatchCtxt<'a, 'p, Cx>,
     /// Type of the place under investigation.
     pub(crate) ty: Cx::Ty,
     /// Whether the place is the original scrutinee place, as opposed to a subplace of it.
@@ -590,12 +581,18 @@ pub(crate) struct PlaceCtxt<'a, 'p, Cx: MatchCx> {
 impl<'a, 'p, Cx: MatchCx> PlaceCtxt<'a, 'p, Cx> {
     /// A `PlaceCtxt` when code other than `is_useful` needs one.
     #[cfg_attr(not(feature = "rustc"), allow(dead_code))]
-    pub(crate) fn new_dummy(
-        cx: &'a Cx,
-        ty: Cx::Ty,
-        wildcard_arena: &'a TypedArena<DeconstructedPat<'p, Cx>>,
-    ) -> Self {
-        PlaceCtxt { cx, ty, is_scrutinee: false, wildcard_arena }
+    pub(crate) fn new_dummy(mcx: MatchCtxt<'a, 'p, Cx>, ty: Cx::Ty) -> Self {
+        PlaceCtxt { mcx, ty, is_scrutinee: false }
+    }
+
+    pub(crate) fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
+        self.mcx.tycx.ctor_arity(ctor, self.ty)
+    }
+    pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
+        self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
+    }
+    pub(crate) fn ctors_for_ty(&self) -> ConstructorSet<Cx> {
+        self.mcx.tycx.ctors_for_ty(self.ty)
     }
 }
 
@@ -1176,11 +1173,10 @@ impl<Cx: MatchCx> WitnessMatrix<Cx> {
 /// - unspecialization, where we lift the results from the previous step into results for this step
 ///     (using `apply_constructor` and by updating `row.useful` for each parent row).
 /// This is all explained at the top of the file.
-#[instrument(level = "debug", skip(cx, is_top_level, wildcard_arena), ret)]
+#[instrument(level = "debug", skip(mcx, is_top_level), ret)]
 fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: MatchCx>(
-    cx: &'a Cx,
+    mcx: MatchCtxt<'a, 'p, Cx>,
     matrix: &mut Matrix<'a, 'p, Cx>,
-    wildcard_arena: &'a TypedArena<DeconstructedPat<'p, Cx>>,
     is_top_level: bool,
 ) -> WitnessMatrix<Cx> {
     debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
@@ -1202,7 +1198,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: MatchCx>(
     };
 
     debug!("ty: {ty:?}");
-    let pcx = &PlaceCtxt { cx, ty, is_scrutinee: is_top_level, wildcard_arena };
+    let pcx = &PlaceCtxt { mcx, ty, is_scrutinee: is_top_level };
 
     // Whether the place/column we are inspecting is known to contain valid data.
     let place_validity = matrix.place_validity[0];
@@ -1211,7 +1207,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: MatchCx>(
 
     // Analyze the constructors present in this column.
     let ctors = matrix.heads().map(|p| p.ctor());
-    let ctors_for_ty = &cx.ctors_for_ty(ty);
+    let ctors_for_ty = pcx.ctors_for_ty();
     let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
     let split_set = ctors_for_ty.split(pcx, ctors);
     let all_missing = split_set.present.is_empty();
@@ -1245,7 +1241,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: MatchCx>(
         // Dig into rows that match `ctor`.
         let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor);
         let mut witnesses = ensure_sufficient_stack(|| {
-            compute_exhaustiveness_and_usefulness(cx, &mut spec_matrix, wildcard_arena, false)
+            compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
         });
 
         let counts_for_exhaustiveness = match ctor {
@@ -1307,17 +1303,15 @@ pub struct UsefulnessReport<'p, Cx: MatchCx> {
 }
 
 /// Computes whether a match is exhaustive and which of its arms are useful.
-#[instrument(skip(cx, arms, wildcard_arena), level = "debug")]
+#[instrument(skip(cx, arms), level = "debug")]
 pub fn compute_match_usefulness<'p, Cx: MatchCx>(
-    cx: &Cx,
+    cx: MatchCtxt<'_, 'p, Cx>,
     arms: &[MatchArm<'p, Cx>],
     scrut_ty: Cx::Ty,
     scrut_validity: ValidityConstraint,
-    wildcard_arena: &TypedArena<DeconstructedPat<'p, Cx>>,
 ) -> UsefulnessReport<'p, Cx> {
-    let mut matrix = Matrix::new(wildcard_arena, arms, scrut_ty, scrut_validity);
-    let non_exhaustiveness_witnesses =
-        compute_exhaustiveness_and_usefulness(cx, &mut matrix, wildcard_arena, true);
+    let mut matrix = Matrix::new(cx.wildcard_arena, arms, scrut_ty, scrut_validity);
+    let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true);
 
     let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
     let arm_usefulness: Vec<_> = arms