Skip to content

Commit 3d7c4df

Browse files
committed
Abstract MatchCheckCtxt into a trait
1 parent 3ad76f9 commit 3d7c4df

File tree

8 files changed

+313
-239
lines changed

8 files changed

+313
-239
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use rustc_pattern_analysis::constructor::Constructor;
2-
use rustc_pattern_analysis::cx::MatchCheckCtxt;
1+
use rustc_pattern_analysis::cx::{
2+
Constructor, DeconstructedPat, MatchCheckCtxt, Usefulness, UsefulnessReport, WitnessPat,
3+
};
34
use rustc_pattern_analysis::errors::Uncovered;
4-
use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
5-
use rustc_pattern_analysis::usefulness::{Usefulness, UsefulnessReport};
65
use rustc_pattern_analysis::{analyze_match, MatchArm};
76

87
use crate::errors::*;
@@ -851,14 +850,15 @@ fn report_arm_reachability<'p, 'tcx>(
851850
);
852851
};
853852

854-
use Usefulness::*;
855853
let mut catchall = None;
856854
for (arm, is_useful) in report.arm_usefulness.iter() {
857855
match is_useful {
858-
Redundant => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall),
859-
Useful(redundant_spans) if redundant_spans.is_empty() => {}
856+
Usefulness::Redundant => {
857+
report_unreachable_pattern(*arm.pat.span(), arm.hir_id, catchall)
858+
}
859+
Usefulness::Useful(redundant_spans) if redundant_spans.is_empty() => {}
860860
// The arm is reachable, but contains redundant subpatterns (from or-patterns).
861-
Useful(redundant_spans) => {
861+
Usefulness::Useful(redundant_spans) => {
862862
let mut redundant_spans = redundant_spans.clone();
863863
// Emit lints in the order in which they occur in the file.
864864
redundant_spans.sort_unstable();
@@ -868,17 +868,16 @@ fn report_arm_reachability<'p, 'tcx>(
868868
}
869869
}
870870
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
871-
catchall = Some(arm.pat.span());
871+
catchall = Some(*arm.pat.span());
872872
}
873873
}
874874
}
875875

876876
/// Checks for common cases of "catchall" patterns that may not be intended as such.
877877
fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
878-
use Constructor::*;
879878
match pat.ctor() {
880-
Wildcard => true,
881-
Struct | Ref => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
879+
Constructor::Wildcard => true,
880+
Constructor::Struct | Constructor::Ref => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
882881
_ => false,
883882
}
884883
}
@@ -889,7 +888,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
889888
thir: &Thir<'tcx>,
890889
scrut_ty: Ty<'tcx>,
891890
sp: Span,
892-
witnesses: Vec<WitnessPat<'tcx>>,
891+
witnesses: Vec<WitnessPat<'p, 'tcx>>,
893892
arms: &[ArmId],
894893
expr_span: Span,
895894
) -> ErrorGuaranteed {
@@ -1086,10 +1085,10 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10861085

10871086
fn joined_uncovered_patterns<'p, 'tcx>(
10881087
cx: &MatchCheckCtxt<'p, 'tcx>,
1089-
witnesses: &[WitnessPat<'tcx>],
1088+
witnesses: &[WitnessPat<'p, 'tcx>],
10901089
) -> String {
10911090
const LIMIT: usize = 3;
1092-
let pat_to_str = |pat: &WitnessPat<'tcx>| cx.hoist_witness_pat(pat).to_string();
1091+
let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.hoist_witness_pat(pat).to_string();
10931092
match witnesses {
10941093
[] => bug!(),
10951094
[witness] => format!("`{}`", cx.hoist_witness_pat(witness)),
@@ -1107,7 +1106,7 @@ fn joined_uncovered_patterns<'p, 'tcx>(
11071106

11081107
fn collect_non_exhaustive_tys<'tcx>(
11091108
cx: &MatchCheckCtxt<'_, 'tcx>,
1110-
pat: &WitnessPat<'tcx>,
1109+
pat: &WitnessPat<'_, 'tcx>,
11111110
non_exhaustive_tys: &mut FxIndexSet<Ty<'tcx>>,
11121111
) {
11131112
if matches!(pat.ctor(), Constructor::NonExhaustive) {
@@ -1126,7 +1125,7 @@ fn collect_non_exhaustive_tys<'tcx>(
11261125
fn report_adt_defined_here<'tcx>(
11271126
tcx: TyCtxt<'tcx>,
11281127
ty: Ty<'tcx>,
1129-
witnesses: &[WitnessPat<'tcx>],
1128+
witnesses: &[WitnessPat<'_, 'tcx>],
11301129
point_at_non_local_ty: bool,
11311130
) -> Option<AdtDefinedHere<'tcx>> {
11321131
let ty = ty.peel_refs();
@@ -1148,15 +1147,14 @@ fn report_adt_defined_here<'tcx>(
11481147
Some(AdtDefinedHere { adt_def_span, ty, variants })
11491148
}
11501149

1151-
fn maybe_point_at_variant<'a, 'tcx: 'a>(
1150+
fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'p>(
11521151
tcx: TyCtxt<'tcx>,
11531152
def: AdtDef<'tcx>,
1154-
patterns: impl Iterator<Item = &'a WitnessPat<'tcx>>,
1153+
patterns: impl Iterator<Item = &'a WitnessPat<'p, 'tcx>>,
11551154
) -> Vec<Span> {
1156-
use Constructor::*;
11571155
let mut covered = vec![];
11581156
for pattern in patterns {
1159-
if let Variant(variant_index) = pattern.ctor() {
1157+
if let Constructor::Variant(variant_index) = pattern.ctor() {
11601158
if let ty::Adt(this_def, _) = pattern.ty().kind()
11611159
&& this_def.did() != def.did()
11621160
{

compiler/rustc_pattern_analysis/src/constructor.rs

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
//! - That have no non-trivial intersection with any of the constructors in the column (i.e. they're
4141
//! each either disjoint with or covered by any given column constructor).
4242
//!
43-
//! We compute this in two steps: first [`crate::cx::MatchCheckCtxt::ctors_for_ty`] determines the
43+
//! We compute this in two steps: first [`MatchCx::ctors_for_ty`] determines the
4444
//! set of all possible constructors for the type. Then [`ConstructorSet::split`] looks at the
4545
//! column of constructors and splits the set into groups accordingly. The precise invariants of
4646
//! [`ConstructorSet::split`] is described in [`SplitConstructorSet`].
@@ -136,7 +136,7 @@
136136
//! the algorithm can't distinguish them from a nonempty constructor. The only known case where this
137137
//! could happen is the `[..]` pattern on `[!; N]` with `N > 0` so we must take care to not emit it.
138138
//!
139-
//! This is all handled by [`crate::cx::MatchCheckCtxt::ctors_for_ty`] and
139+
//! This is all handled by [`MatchCx::ctors_for_ty`] and
140140
//! [`ConstructorSet::split`]. The invariants of [`SplitConstructorSet`] are also of interest.
141141
//!
142142
//!
@@ -158,14 +158,13 @@ use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
158158
use rustc_data_structures::fx::FxHashSet;
159159
use rustc_hir::RangeEnd;
160160
use rustc_index::IndexVec;
161-
use rustc_middle::mir::Const;
162-
use rustc_target::abi::VariantIdx;
163161

164162
use self::Constructor::*;
165163
use self::MaybeInfiniteInt::*;
166164
use self::SliceKind::*;
167165

168166
use crate::usefulness::PatCtxt;
167+
use crate::MatchCx;
169168

170169
/// Whether we have seen a constructor in the column or not.
171170
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -630,11 +629,11 @@ impl OpaqueId {
630629
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
631630
/// `Fields`.
632631
#[derive(Clone, Debug, PartialEq)]
633-
pub enum Constructor<'tcx> {
632+
pub enum Constructor<Cx: MatchCx> {
634633
/// Tuples and structs.
635634
Struct,
636635
/// Enum variants.
637-
Variant(VariantIdx),
636+
Variant(Cx::VariantIdx),
638637
/// References
639638
Ref,
640639
/// Array and slice patterns.
@@ -649,7 +648,7 @@ pub enum Constructor<'tcx> {
649648
F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd),
650649
F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
651650
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
652-
Str(Const<'tcx>),
651+
Str(Cx::StrLit),
653652
/// Constants that must not be matched structurally. They are treated as black boxes for the
654653
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
655654
/// match exhaustive.
@@ -672,12 +671,12 @@ pub enum Constructor<'tcx> {
672671
Missing,
673672
}
674673

675-
impl<'tcx> Constructor<'tcx> {
674+
impl<Cx: MatchCx> Constructor<Cx> {
676675
pub(crate) fn is_non_exhaustive(&self) -> bool {
677676
matches!(self, NonExhaustive)
678677
}
679678

680-
pub(crate) fn as_variant(&self) -> Option<VariantIdx> {
679+
pub(crate) fn as_variant(&self) -> Option<Cx::VariantIdx> {
681680
match self {
682681
Variant(i) => Some(*i),
683682
_ => None,
@@ -704,7 +703,7 @@ impl<'tcx> Constructor<'tcx> {
704703

705704
/// The number of fields for this constructor. This must be kept in sync with
706705
/// `Fields::wildcards`.
707-
pub(crate) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
706+
pub(crate) fn arity(&self, pcx: &PatCtxt<'_, '_, Cx>) -> usize {
708707
pcx.cx.ctor_arity(self, pcx.ty)
709708
}
710709

@@ -713,14 +712,11 @@ impl<'tcx> Constructor<'tcx> {
713712
/// this checks for inclusion.
714713
// We inline because this has a single call site in `Matrix::specialize_constructor`.
715714
#[inline]
716-
pub(crate) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
715+
pub(crate) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, Cx>, other: &Self) -> bool {
717716
match (self, other) {
718-
(Wildcard, _) => {
719-
span_bug!(
720-
pcx.cx.scrut_span,
721-
"Constructor splitting should not have returned `Wildcard`"
722-
)
723-
}
717+
(Wildcard, _) => pcx
718+
.cx
719+
.bug(format_args!("Constructor splitting should not have returned `Wildcard`")),
724720
// Wildcards cover anything
725721
(_, Wildcard) => true,
726722
// Only a wildcard pattern can match these special constructors.
@@ -761,12 +757,9 @@ impl<'tcx> Constructor<'tcx> {
761757
(Opaque(self_id), Opaque(other_id)) => self_id == other_id,
762758
(Opaque(..), _) | (_, Opaque(..)) => false,
763759

764-
_ => span_bug!(
765-
pcx.cx.scrut_span,
766-
"trying to compare incompatible constructors {:?} and {:?}",
767-
self,
768-
other
769-
),
760+
_ => pcx.cx.bug(format_args!(
761+
"trying to compare incompatible constructors {self:?} and {other:?}"
762+
)),
770763
}
771764
}
772765
}
@@ -790,12 +783,12 @@ pub enum VariantVisibility {
790783
/// In terms of division of responsibility, [`ConstructorSet::split`] handles all of the
791784
/// `exhaustive_patterns` feature.
792785
#[derive(Debug)]
793-
pub enum ConstructorSet {
786+
pub enum ConstructorSet<Cx: MatchCx> {
794787
/// The type is a tuple or struct. `empty` tracks whether the type is empty.
795788
Struct { empty: bool },
796789
/// This type has the following list of constructors. If `variants` is empty and
797790
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
798-
Variants { variants: IndexVec<VariantIdx, VariantVisibility>, non_exhaustive: bool },
791+
Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
799792
/// The type is `&T`.
800793
Ref,
801794
/// The type is a union.
@@ -838,25 +831,25 @@ pub enum ConstructorSet {
838831
/// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be
839832
/// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4.
840833
#[derive(Debug)]
841-
pub(crate) struct SplitConstructorSet<'tcx> {
842-
pub(crate) present: SmallVec<[Constructor<'tcx>; 1]>,
843-
pub(crate) missing: Vec<Constructor<'tcx>>,
844-
pub(crate) missing_empty: Vec<Constructor<'tcx>>,
834+
pub(crate) struct SplitConstructorSet<Cx: MatchCx> {
835+
pub(crate) present: SmallVec<[Constructor<Cx>; 1]>,
836+
pub(crate) missing: Vec<Constructor<Cx>>,
837+
pub(crate) missing_empty: Vec<Constructor<Cx>>,
845838
}
846839

847-
impl ConstructorSet {
840+
impl<Cx: MatchCx> ConstructorSet<Cx> {
848841
/// This analyzes a column of constructors to 1/ determine which constructors of the type (if
849842
/// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
850843
/// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
851844
/// and its invariants.
852845
#[instrument(level = "debug", skip(self, pcx, ctors), ret)]
853-
pub(crate) fn split<'a, 'tcx>(
846+
pub(crate) fn split<'a>(
854847
&self,
855-
pcx: &PatCtxt<'_, '_, 'tcx>,
856-
ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
857-
) -> SplitConstructorSet<'tcx>
848+
pcx: &PatCtxt<'_, '_, Cx>,
849+
ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
850+
) -> SplitConstructorSet<Cx>
858851
where
859-
'tcx: 'a,
852+
Cx: 'a,
860853
{
861854
let mut present: SmallVec<[_; 1]> = SmallVec::new();
862855
// Empty constructors found missing.
@@ -997,7 +990,7 @@ impl ConstructorSet {
997990
// We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
998991
// In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
999992
// types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
1000-
if !pcx.cx.tcx.features().exhaustive_patterns
993+
if !pcx.cx.is_exhaustive_patterns_feature_on()
1001994
&& !(pcx.is_top_level && matches!(self, Self::NoConstructors))
1002995
{
1003996
// Treat all missing constructors as nonempty.

0 commit comments

Comments
 (0)