Pass Matrix explicitly instead of via PatCtxt

This commit is contained in:
Nadrieril 2020-12-20 14:29:42 +00:00
parent 8b38b6859a
commit 43d445c8d1
2 changed files with 48 additions and 27 deletions

View File

@ -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<Item = (&'a Constructor<'tcx>, 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<Item = &'a Constructor<'tcx>> + 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<Item = &'a Constructor<'tcx>> + 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.

View File

@ -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<Item = &'a Constructor<'tcx>> + Captures<'p> {
) -> impl Iterator<Item = &'a Constructor<'tcx>> + 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)
};