Pass Matrix
explicitly instead of via PatCtxt
This commit is contained in:
parent
8b38b6859a
commit
43d445c8d1
|
@ -19,7 +19,7 @@ use rustc_middle::mir::Field;
|
||||||
use rustc_middle::ty::layout::IntegerExt;
|
use rustc_middle::ty::layout::IntegerExt;
|
||||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::abi::{Integer, Size, VariantIdx};
|
use rustc_target::abi::{Integer, Size, VariantIdx};
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
@ -184,12 +184,18 @@ impl IntRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lint on likely incorrect range patterns (#63987)
|
/// 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() {
|
if self.is_singleton() {
|
||||||
return;
|
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
|
// FIXME: for now, only check for overlapping ranges on simple range
|
||||||
// patterns. Otherwise with the current logic the following is detected
|
// patterns. Otherwise with the current logic the following is detected
|
||||||
// as overlapping:
|
// as overlapping:
|
||||||
|
@ -203,9 +209,7 @@ impl IntRange {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let overlaps: Vec<_> = pcx
|
let overlaps: Vec<_> = ctors
|
||||||
.matrix
|
|
||||||
.head_ctors_and_spans(pcx.cx)
|
|
||||||
.filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
|
.filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
|
||||||
.filter(|(range, _)| self.suspicious_intersection(range))
|
.filter(|(range, _)| self.suspicious_intersection(range))
|
||||||
.map(|(range, span)| (self.intersection(&range).unwrap(), span))
|
.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
|
/// 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
|
/// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the
|
||||||
/// matrix, unless all of them are.
|
/// matrix, unless all of them are.
|
||||||
pub(super) fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> {
|
pub(super) fn split<'a>(
|
||||||
debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
|
&self,
|
||||||
|
pcx: PatCtxt<'_, '_, 'tcx>,
|
||||||
|
ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
|
||||||
|
) -> SmallVec<[Self; 1]>
|
||||||
|
where
|
||||||
|
'tcx: 'a,
|
||||||
|
{
|
||||||
|
debug!("Constructor::split({:#?})", self);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Wildcard => {
|
Wildcard => {
|
||||||
let mut split_wildcard = SplitWildcard::new(pcx);
|
let mut split_wildcard = SplitWildcard::new(pcx);
|
||||||
split_wildcard.split(pcx);
|
split_wildcard.split(pcx, ctors);
|
||||||
split_wildcard.into_ctors(pcx)
|
split_wildcard.into_ctors(pcx)
|
||||||
}
|
}
|
||||||
// Fast-track if the range is trivial. In particular, we don't do the overlapping
|
// Fast-track if the range is trivial. In particular, we don't do the overlapping
|
||||||
// ranges check.
|
// ranges check.
|
||||||
IntRange(ctor_range) if !ctor_range.is_singleton() => {
|
IntRange(ctor_range) if !ctor_range.is_singleton() => {
|
||||||
let mut split_range = SplitIntRange::new(ctor_range.clone());
|
let mut split_range = SplitIntRange::new(ctor_range.clone());
|
||||||
let intranges =
|
let intranges = ctors.filter_map(|ctor| ctor.as_int_range());
|
||||||
pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range());
|
|
||||||
split_range.split(intranges.cloned());
|
split_range.split(intranges.cloned());
|
||||||
split_range.iter().map(IntRange).collect()
|
split_range.iter().map(IntRange).collect()
|
||||||
}
|
}
|
||||||
&Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => {
|
&Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => {
|
||||||
let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len);
|
let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len);
|
||||||
let slices =
|
let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind);
|
||||||
pcx.matrix.head_ctors(pcx.cx).filter_map(|c| c.as_slice()).map(|s| s.kind);
|
|
||||||
split_self.split(slices);
|
split_self.split(slices);
|
||||||
split_self.iter().map(Slice).collect()
|
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
|
/// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
|
||||||
/// do what you want.
|
/// do what you want.
|
||||||
pub(super) fn split(&mut self, pcx: PatCtxt<'_, '_, 'tcx>) {
|
pub(super) fn split<'a>(
|
||||||
self.matrix_ctors =
|
&mut self,
|
||||||
pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
|
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.
|
// 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.
|
/// Whether there are any value constructors for this type that are not present in the matrix.
|
||||||
|
|
|
@ -358,8 +358,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(super) struct PatCtxt<'a, 'p, 'tcx> {
|
pub(super) struct PatCtxt<'a, 'p, 'tcx> {
|
||||||
pub(super) cx: &'a MatchCheckCtxt<'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.
|
/// Type of the current column under investigation.
|
||||||
pub(super) ty: Ty<'tcx>,
|
pub(super) ty: Ty<'tcx>,
|
||||||
/// Span of the current pattern under investigation.
|
/// Span of the current pattern under investigation.
|
||||||
|
@ -538,7 +536,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
pub(super) fn head_ctors<'a>(
|
pub(super) fn head_ctors<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a MatchCheckCtxt<'p, 'tcx>,
|
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))
|
self.patterns.iter().map(move |r| r.head_ctor(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,6 +802,7 @@ impl<'tcx> Usefulness<'tcx> {
|
||||||
fn apply_constructor<'p>(
|
fn apply_constructor<'p>(
|
||||||
self,
|
self,
|
||||||
pcx: PatCtxt<'_, 'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
|
matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
|
||||||
ctor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -811,7 +810,7 @@ impl<'tcx> Usefulness<'tcx> {
|
||||||
UsefulWithWitness(witnesses) => {
|
UsefulWithWitness(witnesses) => {
|
||||||
let new_witnesses = if ctor.is_wildcard() {
|
let new_witnesses = if ctor.is_wildcard() {
|
||||||
let mut split_wildcard = SplitWildcard::new(pcx);
|
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);
|
let new_patterns = split_wildcard.report_missing_patterns(pcx);
|
||||||
witnesses
|
witnesses
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -968,7 +967,7 @@ fn is_useful<'p, 'tcx>(
|
||||||
|
|
||||||
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
|
// 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 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());
|
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);
|
let v_ctor = v.head_ctor(cx);
|
||||||
if let Constructor::IntRange(ctor_range) = &v_ctor {
|
if let Constructor::IntRange(ctor_range) = &v_ctor {
|
||||||
// Lint on likely incorrect range patterns (#63987)
|
// 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`.
|
// 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
|
// For each constructor, we compute whether there's a value that starts with it that would
|
||||||
// witness the usefulness of `v`.
|
// witness the usefulness of `v`.
|
||||||
|
let start_matrix = &matrix;
|
||||||
let usefulnesses = split_ctors.into_iter().map(|ctor| {
|
let usefulnesses = split_ctors.into_iter().map(|ctor| {
|
||||||
// We cache the result of `Fields::wildcards` because it is used a lot.
|
// We cache the result of `Fields::wildcards` because it is used a lot.
|
||||||
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
|
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 v = v.pop_head_constructor(&ctor_wild_subpatterns);
|
||||||
let usefulness =
|
let usefulness =
|
||||||
is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
|
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
|
||||||
usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
|
usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns)
|
||||||
});
|
});
|
||||||
Usefulness::merge(usefulnesses)
|
Usefulness::merge(usefulnesses)
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue