diff options
Diffstat (limited to 'compiler/rustc_pattern_analysis/src/usefulness.rs')
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/usefulness.rs | 68 | 
1 files changed, 39 insertions, 29 deletions
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index b15de1c0ca9..3d45d032a99 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -719,7 +719,7 @@ use std::fmt; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat}; -use crate::{Captures, MatchArm, MatchCtxt, TypeCx}; +use crate::{Captures, MatchArm, TypeCx}; use self::ValidityConstraint::*; @@ -730,21 +730,33 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R { f() } +/// Context that provides information for usefulness checking. +pub struct UsefulnessCtxt<'a, Cx: TypeCx> { + /// The context for type information. + pub tycx: &'a Cx, +} + +impl<'a, Cx: TypeCx> Copy for UsefulnessCtxt<'a, Cx> {} +impl<'a, Cx: TypeCx> Clone for UsefulnessCtxt<'a, Cx> { + fn clone(&self) -> Self { + Self { tycx: self.tycx } + } +} + /// Context that provides information local to a place under investigation. -pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> { - pub(crate) mcx: MatchCtxt<'a, Cx>, +struct PlaceCtxt<'a, Cx: TypeCx> { + cx: &'a Cx, /// Type of the place under investigation. - pub(crate) ty: &'a Cx::Ty, + ty: &'a Cx::Ty, } +impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {} impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> { fn clone(&self) -> Self { - Self { mcx: self.mcx, ty: self.ty } + Self { cx: self.cx, ty: self.ty } } } -impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {} - impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish() @@ -752,23 +764,20 @@ impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> { } impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { - /// A `PlaceCtxt` when code other than `is_useful` needs one. - #[cfg_attr(not(feature = "rustc"), allow(dead_code))] - pub(crate) fn new_dummy(mcx: MatchCtxt<'a, Cx>, ty: &'a Cx::Ty) -> Self { - PlaceCtxt { mcx, ty } + fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize { + self.cx.ctor_arity(ctor, self.ty) } - - pub(crate) fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize { - self.mcx.tycx.ctor_arity(ctor, self.ty) - } - pub(crate) fn ctor_sub_tys( + fn ctor_sub_tys( &'a self, ctor: &'a Constructor<Cx>, ) -> impl Iterator<Item = Cx::Ty> + ExactSizeIterator + Captures<'a> { - self.mcx.tycx.ctor_sub_tys(ctor, self.ty) + self.cx.ctor_sub_tys(ctor, self.ty) + } + fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> { + self.cx.ctors_for_ty(self.ty) } - pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> { - self.mcx.tycx.ctors_for_ty(self.ty) + fn wild_from_ctor(&self, ctor: Constructor<Cx>) -> WitnessPat<Cx> { + WitnessPat::wild_from_ctor(self.cx, ctor, self.ty.clone()) } } @@ -1089,7 +1098,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant, }; for (i, row) in self.rows().enumerate() { - if ctor.is_covered_by(pcx, row.head().ctor()) { + if ctor.is_covered_by(pcx.cx, row.head().ctor()) { let new_row = row.pop_head_constructor(ctor, arity, ctor_is_relevant, i); matrix.expand_and_push(new_row); } @@ -1240,7 +1249,7 @@ impl<Cx: TypeCx> WitnessStack<Cx> { /// ``` fn apply_constructor(&mut self, pcx: &PlaceCtxt<'_, Cx>, ctor: &Constructor<Cx>) { let len = self.0.len(); - let arity = ctor.arity(pcx); + let arity = pcx.ctor_arity(ctor); let fields = self.0.drain((len - arity)..).rev().collect(); let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty.clone()); self.0.push(pat); @@ -1315,20 +1324,20 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> { *self = Self::empty(); } else if !report_individual_missing_ctors { // Report `_` as missing. - let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard); + let pat = pcx.wild_from_ctor(Constructor::Wildcard); self.push_pattern(pat); } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { // We need to report a `_` anyway, so listing other constructors would be redundant. // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked // up by diagnostics to add a note about why `_` is required here. - let pat = WitnessPat::wild_from_ctor(pcx, Constructor::NonExhaustive); + let pat = pcx.wild_from_ctor(Constructor::NonExhaustive); self.push_pattern(pat); } else { // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately // filled with wildcards. let mut ret = Self::empty(); for ctor in missing_ctors { - let pat = WitnessPat::wild_from_ctor(pcx, ctor.clone()); + let pat = pcx.wild_from_ctor(ctor.clone()); // Clone `self` and add `c(_, _, _)` to each of its witnesses. let mut wit_matrix = self.clone(); wit_matrix.push_pattern(pat); @@ -1362,7 +1371,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> { /// We can however get false negatives because exhaustiveness does not explore all cases. See the /// section on relevancy at the top of the file. fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( - mcx: MatchCtxt<'_, Cx>, + mcx: UsefulnessCtxt<'_, Cx>, overlap_range: IntRange, matrix: &Matrix<'p, Cx>, specialized_matrix: &Matrix<'p, Cx>, @@ -1435,7 +1444,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( /// This is all explained at the top of the file. #[instrument(level = "debug", skip(mcx, is_top_level), ret)] fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( - mcx: MatchCtxt<'a, Cx>, + mcx: UsefulnessCtxt<'a, Cx>, matrix: &mut Matrix<'p, Cx>, is_top_level: bool, ) -> Result<WitnessMatrix<Cx>, Cx::Error> { @@ -1469,7 +1478,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( }; debug!("ty: {ty:?}"); - let pcx = &PlaceCtxt { mcx, ty: &ty }; + let pcx = &PlaceCtxt { cx: mcx.tycx, ty: &ty }; let ctors_for_ty = pcx.ctors_for_ty()?; // Whether the place/column we are inspecting is known to contain valid data. @@ -1592,13 +1601,14 @@ pub struct UsefulnessReport<'p, Cx: TypeCx> { } /// Computes whether a match is exhaustive and which of its arms are useful. -#[instrument(skip(cx, arms), level = "debug")] +#[instrument(skip(tycx, arms), level = "debug")] pub fn compute_match_usefulness<'p, Cx: TypeCx>( - cx: MatchCtxt<'_, Cx>, + tycx: &Cx, arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> { + let cx = UsefulnessCtxt { tycx }; let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;  | 
