From 43d445c8d1ae9c6ecb8203dd97d96f0e245b042d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Dec 2020 14:29:42 +0000 Subject: [PATCH] Pass `Matrix` explicitly instead of via `PatCtxt` --- .../src/thir/pattern/deconstruct_pat.rs | 49 ++++++++++++------- .../src/thir/pattern/usefulness.rs | 26 ++++++---- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 060e4fdf6f8..4860bb0fe87 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; @@ -184,12 +184,18 @@ impl IntRange { } /// Lint on likely incorrect range patterns (#63987) - pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>, hir_id: HirId) { + pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>( + &self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator, Span)>, + column_count: usize, + hir_id: HirId, + ) { if self.is_singleton() { return; } - if pcx.matrix.column_count().unwrap_or(0) != 1 { + if column_count != 1 { // FIXME: for now, only check for overlapping ranges on simple range // patterns. Otherwise with the current logic the following is detected // as overlapping: @@ -203,9 +209,7 @@ impl IntRange { return; } - let overlaps: Vec<_> = pcx - .matrix - .head_ctors_and_spans(pcx.cx) + let overlaps: Vec<_> = ctors .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) .filter(|(range, _)| self.suspicious_intersection(range)) .map(|(range, span)| (self.intersection(&range).unwrap(), span)) @@ -655,28 +659,33 @@ impl<'tcx> Constructor<'tcx> { /// This function may discard some irrelevant constructors if this preserves behavior and /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the /// matrix, unless all of them are. - pub(super) fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { - debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); + pub(super) fn split<'a>( + &self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator> + Clone, + ) -> SmallVec<[Self; 1]> + where + 'tcx: 'a, + { + debug!("Constructor::split({:#?})", self); match self { Wildcard => { let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx); + split_wildcard.split(pcx, ctors); split_wildcard.into_ctors(pcx) } // Fast-track if the range is trivial. In particular, we don't do the overlapping // ranges check. IntRange(ctor_range) if !ctor_range.is_singleton() => { let mut split_range = SplitIntRange::new(ctor_range.clone()); - let intranges = - pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range()); + let intranges = ctors.filter_map(|ctor| ctor.as_int_range()); split_range.split(intranges.cloned()); split_range.iter().map(IntRange).collect() } &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); - let slices = - pcx.matrix.head_ctors(pcx.cx).filter_map(|c| c.as_slice()).map(|s| s.kind); + let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind); split_self.split(slices); split_self.iter().map(Slice).collect() } @@ -912,11 +921,17 @@ impl<'tcx> SplitWildcard<'tcx> { /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't /// do what you want. - pub(super) fn split(&mut self, pcx: PatCtxt<'_, '_, 'tcx>) { - self.matrix_ctors = - pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); + pub(super) fn split<'a>( + &mut self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator> + Clone, + ) where + 'tcx: 'a, + { // Since `all_ctors` never contains wildcards, this won't recurse further. - self.all_ctors = self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx)).collect(); + self.all_ctors = + self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); + self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect(); } /// Whether there are any value constructors for this type that are not present in the matrix. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 5da42e705df..ad672b59ba4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -358,8 +358,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { #[derive(Copy, Clone)] pub(super) struct PatCtxt<'a, 'p, 'tcx> { pub(super) cx: &'a MatchCheckCtxt<'p, 'tcx>, - /// Current state of the matrix. - pub(super) matrix: &'a Matrix<'p, 'tcx>, /// Type of the current column under investigation. pub(super) ty: Ty<'tcx>, /// Span of the current pattern under investigation. @@ -538,7 +536,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { pub(super) fn head_ctors<'a>( &'a self, cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator> + Captures<'p> { + ) -> impl Iterator> + Captures<'p> + Clone { self.patterns.iter().map(move |r| r.head_ctor(cx)) } @@ -804,6 +802,7 @@ impl<'tcx> Usefulness<'tcx> { fn apply_constructor<'p>( self, pcx: PatCtxt<'_, 'p, 'tcx>, + matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors ctor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Self { @@ -811,7 +810,7 @@ impl<'tcx> Usefulness<'tcx> { UsefulWithWitness(witnesses) => { let new_witnesses = if ctor.is_wildcard() { let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx); + split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); let new_patterns = split_wildcard.report_missing_patterns(pcx); witnesses .into_iter() @@ -968,7 +967,7 @@ fn is_useful<'p, 'tcx>( // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); - let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level }; + let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); @@ -995,20 +994,27 @@ fn is_useful<'p, 'tcx>( let v_ctor = v.head_ctor(cx); if let Constructor::IntRange(ctor_range) = &v_ctor { // Lint on likely incorrect range patterns (#63987) - ctor_range.lint_overlapping_range_endpoints(pcx, hir_id) + ctor_range.lint_overlapping_range_endpoints( + pcx, + matrix.head_ctors_and_spans(cx), + matrix.column_count().unwrap_or(0), + hir_id, + ) } // We split the head constructor of `v`. - let split_ctors = v_ctor.split(pcx); + let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx)); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. + let start_matrix = &matrix; let usefulnesses = split_ctors.into_iter().map(|ctor| { // We cache the result of `Fields::wildcards` because it is used a lot. let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); + let spec_matrix = + start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); let v = v.pop_head_constructor(&ctor_wild_subpatterns); let usefulness = - is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) + is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false); + usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns) }); Usefulness::merge(usefulnesses) };