Pass Matrix
explicitly instead of via PatCtxt
This commit is contained in:
parent
8b38b6859a
commit
43d445c8d1
@ -19,7 +19,7 @@
|
||||
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 @@ fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
||||
}
|
||||
|
||||
/// 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 @@ pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>,
|
||||
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 @@ pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'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 @@ pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
|
||||
|
||||
/// 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.
|
||||
|
@ -358,8 +358,6 @@ pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
|
||||
#[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 @@ fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
|
||||
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 @@ fn unsplit_or_pat(self, this_span: Span, or_pat_spans: &[Span]) -> Self {
|
||||
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 @@ fn apply_constructor<'p>(
|
||||
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)
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user