Pass more things through PatCtxt
This is even a perf improvement on the match-heavy benchmarks.
This commit is contained in:
parent
cdafd1e1bd
commit
b49f90760d
1 changed files with 75 additions and 128 deletions
|
@ -417,7 +417,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
|
||||||
/// This is roughly the inverse of `Constructor::apply`.
|
/// This is roughly the inverse of `Constructor::apply`.
|
||||||
fn specialize_constructor(
|
fn specialize_constructor(
|
||||||
&self,
|
&self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
ctor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
is_my_head_ctor: bool,
|
is_my_head_ctor: bool,
|
||||||
|
@ -428,7 +428,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
|
||||||
// Note that this shortcut is also necessary for correctness: a pattern should always be
|
// Note that this shortcut is also necessary for correctness: a pattern should always be
|
||||||
// specializable with its own constructor, even in cases where we refuse to inspect values like
|
// specializable with its own constructor, even in cases where we refuse to inspect values like
|
||||||
// opaque constants.
|
// opaque constants.
|
||||||
if !is_my_head_ctor && !ctor.is_covered_by(cx, self.head_ctor(cx), self.head().ty) {
|
if !is_my_head_ctor && !ctor.is_covered_by(pcx, self.head_ctor(pcx.cx)) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let new_fields = ctor_wild_subpatterns.replace_with_pattern_arguments(self.head());
|
let new_fields = ctor_wild_subpatterns.replace_with_pattern_arguments(self.head());
|
||||||
|
@ -593,7 +593,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
||||||
fn specialize_constructor(
|
fn specialize_constructor(
|
||||||
&self,
|
&self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
constructor: &Constructor<'tcx>,
|
constructor: &Constructor<'tcx>,
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
) -> Matrix<'p, 'tcx> {
|
) -> Matrix<'p, 'tcx> {
|
||||||
|
@ -616,7 +616,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&i| {
|
.filter_map(|&i| {
|
||||||
self.patterns[i].specialize_constructor(
|
self.patterns[i].specialize_constructor(
|
||||||
cx,
|
pcx,
|
||||||
constructor,
|
constructor,
|
||||||
ctor_wild_subpatterns,
|
ctor_wild_subpatterns,
|
||||||
false,
|
false,
|
||||||
|
@ -632,7 +632,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
cache: SpecializationCache::Incompatible
|
cache: SpecializationCache::Incompatible
|
||||||
}
|
}
|
||||||
.specialize_constructor(
|
.specialize_constructor(
|
||||||
cx,
|
pcx,
|
||||||
constructor,
|
constructor,
|
||||||
ctor_wild_subpatterns
|
ctor_wild_subpatterns
|
||||||
)
|
)
|
||||||
|
@ -643,7 +643,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
.patterns
|
.patterns
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|r| {
|
.filter_map(|r| {
|
||||||
r.specialize_constructor(cx, constructor, ctor_wild_subpatterns, false)
|
r.specialize_constructor(pcx, constructor, ctor_wild_subpatterns, false)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
|
@ -914,11 +914,7 @@ impl Slice {
|
||||||
/// but the first and last can be added/removed, so any
|
/// but the first and last can be added/removed, so any
|
||||||
/// witness of length ≥2 (say, `[false, false, true]`) can be
|
/// witness of length ≥2 (say, `[false, false, true]`) can be
|
||||||
/// turned to a witness from any other length ≥2.
|
/// turned to a witness from any other length ≥2.
|
||||||
fn split<'p, 'tcx>(
|
fn split<'p, 'tcx>(self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
|
||||||
self,
|
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
matrix: &Matrix<'p, 'tcx>,
|
|
||||||
) -> SmallVec<[Constructor<'tcx>; 1]> {
|
|
||||||
let (array_len, self_prefix, self_suffix) = match self {
|
let (array_len, self_prefix, self_suffix) = match self {
|
||||||
Slice { array_len, kind: VarLen(self_prefix, self_suffix) } => {
|
Slice { array_len, kind: VarLen(self_prefix, self_suffix) } => {
|
||||||
(array_len, self_prefix, self_suffix)
|
(array_len, self_prefix, self_suffix)
|
||||||
|
@ -926,7 +922,7 @@ impl Slice {
|
||||||
_ => return smallvec![Slice(self)],
|
_ => return smallvec![Slice(self)],
|
||||||
};
|
};
|
||||||
|
|
||||||
let head_ctors = matrix.head_ctors(cx).filter(|c| !c.is_wildcard());
|
let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard());
|
||||||
|
|
||||||
let mut max_prefix_len = self_prefix;
|
let mut max_prefix_len = self_prefix;
|
||||||
let mut max_suffix_len = self_suffix;
|
let mut max_suffix_len = self_suffix;
|
||||||
|
@ -1136,24 +1132,18 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
///
|
///
|
||||||
/// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want
|
/// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want
|
||||||
/// to lint for overlapping ranges.
|
/// to lint for overlapping ranges.
|
||||||
fn split<'p>(
|
fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, hir_id: Option<HirId>) -> SmallVec<[Self; 1]> {
|
||||||
&self,
|
debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
pcx: PatCtxt<'tcx>,
|
|
||||||
matrix: &Matrix<'p, 'tcx>,
|
|
||||||
hir_id: Option<HirId>,
|
|
||||||
) -> SmallVec<[Self; 1]> {
|
|
||||||
debug!("Constructor::split({:#?}, {:#?})", self, matrix);
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
// 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)
|
IntRange(ctor_range)
|
||||||
if ctor_range.treat_exhaustively(cx.tcx) && !ctor_range.is_singleton() =>
|
if ctor_range.treat_exhaustively(pcx.cx.tcx) && !ctor_range.is_singleton() =>
|
||||||
{
|
{
|
||||||
ctor_range.split(cx, pcx, matrix, hir_id)
|
ctor_range.split(pcx, hir_id)
|
||||||
}
|
}
|
||||||
Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(cx, matrix),
|
Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
|
||||||
// Any other constructor can be used unchanged.
|
// Any other constructor can be used unchanged.
|
||||||
_ => smallvec![self.clone()],
|
_ => smallvec![self.clone()],
|
||||||
}
|
}
|
||||||
|
@ -1162,12 +1152,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
/// Returns whether `self` is covered by `other`, ie whether `self` is a subset of `other`. For
|
/// Returns whether `self` is covered by `other`, ie whether `self` is a subset of `other`. For
|
||||||
/// the simple cases, this is simply checking for equality. For the "grouped" constructors,
|
/// the simple cases, this is simply checking for equality. For the "grouped" constructors,
|
||||||
/// this checks for inclusion.
|
/// this checks for inclusion.
|
||||||
fn is_covered_by<'p>(
|
fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Constructor<'tcx>) -> bool {
|
||||||
&self,
|
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
other: &Constructor<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
// Wildcards cover anything
|
// Wildcards cover anything
|
||||||
(_, Wildcard) => true,
|
(_, Wildcard) => true,
|
||||||
|
@ -1178,7 +1163,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
||||||
|
|
||||||
(IntRange(self_range), IntRange(other_range)) => {
|
(IntRange(self_range), IntRange(other_range)) => {
|
||||||
if self_range.intersection(cx.tcx, other_range).is_some() {
|
if self_range.intersection(pcx.cx.tcx, other_range).is_some() {
|
||||||
// Constructor splitting should ensure that all intersections we encounter
|
// Constructor splitting should ensure that all intersections we encounter
|
||||||
// are actually inclusions.
|
// are actually inclusions.
|
||||||
assert!(self_range.is_subrange(other_range));
|
assert!(self_range.is_subrange(other_range));
|
||||||
|
@ -1192,8 +1177,8 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
FloatRange(other_from, other_to, other_end),
|
FloatRange(other_from, other_to, other_end),
|
||||||
) => {
|
) => {
|
||||||
match (
|
match (
|
||||||
compare_const_vals(cx.tcx, self_to, other_to, cx.param_env, ty),
|
compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
|
||||||
compare_const_vals(cx.tcx, self_from, other_from, cx.param_env, ty),
|
compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
|
||||||
) {
|
) {
|
||||||
(Some(to), Some(from)) => {
|
(Some(to), Some(from)) => {
|
||||||
(from == Ordering::Greater || from == Ordering::Equal)
|
(from == Ordering::Greater || from == Ordering::Equal)
|
||||||
|
@ -1205,7 +1190,8 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
}
|
}
|
||||||
(Str(self_val), Str(other_val)) => {
|
(Str(self_val), Str(other_val)) => {
|
||||||
// FIXME: there's probably a more direct way of comparing for equality
|
// FIXME: there's probably a more direct way of comparing for equality
|
||||||
match compare_const_vals(cx.tcx, self_val, other_val, cx.param_env, ty) {
|
match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty)
|
||||||
|
{
|
||||||
Some(comparison) => comparison == Ordering::Equal,
|
Some(comparison) => comparison == Ordering::Equal,
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
|
@ -1239,23 +1225,18 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
/// `ty`: `Option<bool>`
|
/// `ty`: `Option<bool>`
|
||||||
/// `pats`: `[false]`
|
/// `pats`: `[false]`
|
||||||
/// returns `Some(false)`
|
/// returns `Some(false)`
|
||||||
fn apply<'p>(
|
fn apply<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, fields: Fields<'p, 'tcx>) -> Pat<'tcx> {
|
||||||
&self,
|
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
fields: Fields<'p, 'tcx>,
|
|
||||||
) -> Pat<'tcx> {
|
|
||||||
let mut subpatterns = fields.all_patterns();
|
let mut subpatterns = fields.all_patterns();
|
||||||
|
|
||||||
let pat = match self {
|
let pat = match self {
|
||||||
Single | Variant(_) => match ty.kind() {
|
Single | Variant(_) => match pcx.ty.kind() {
|
||||||
ty::Adt(..) | ty::Tuple(..) => {
|
ty::Adt(..) | ty::Tuple(..) => {
|
||||||
let subpatterns = subpatterns
|
let subpatterns = subpatterns
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
|
.map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let ty::Adt(adt, substs) = ty.kind() {
|
if let ty::Adt(adt, substs) = pcx.ty.kind() {
|
||||||
if adt.is_enum() {
|
if adt.is_enum() {
|
||||||
PatKind::Variant {
|
PatKind::Variant {
|
||||||
adt_def: adt,
|
adt_def: adt,
|
||||||
|
@ -1271,7 +1252,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
|
ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
|
||||||
ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
|
ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, pcx.ty),
|
||||||
_ => PatKind::Wild,
|
_ => PatKind::Wild,
|
||||||
},
|
},
|
||||||
Slice(slice) => match slice.pattern_kind() {
|
Slice(slice) => match slice.pattern_kind() {
|
||||||
|
@ -1295,19 +1276,19 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
} else {
|
} else {
|
||||||
subpatterns.collect()
|
subpatterns.collect()
|
||||||
};
|
};
|
||||||
let wild = Pat::wildcard_from_ty(ty);
|
let wild = Pat::wildcard_from_ty(pcx.ty);
|
||||||
PatKind::Slice { prefix, slice: Some(wild), suffix }
|
PatKind::Slice { prefix, slice: Some(wild), suffix }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&Str(value) => PatKind::Constant { value },
|
&Str(value) => PatKind::Constant { value },
|
||||||
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
|
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
|
||||||
IntRange(range) => return range.to_pat(cx.tcx),
|
IntRange(range) => return range.to_pat(pcx.cx.tcx),
|
||||||
NonExhaustive => PatKind::Wild,
|
NonExhaustive => PatKind::Wild,
|
||||||
Opaque => bug!("we should not try to apply an opaque constructor"),
|
Opaque => bug!("we should not try to apply an opaque constructor"),
|
||||||
Wildcard => bug!("we should not try to apply a wildcard constructor"),
|
Wildcard => bug!("we should not try to apply a wildcard constructor"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
|
Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1385,11 +1366,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new list of wildcard fields for a given constructor.
|
/// Creates a new list of wildcard fields for a given constructor.
|
||||||
fn wildcards(
|
fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
let ty = pcx.ty;
|
||||||
constructor: &Constructor<'tcx>,
|
let cx = pcx.cx;
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> Self {
|
|
||||||
let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
|
let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
|
||||||
|
|
||||||
let ret = match constructor {
|
let ret = match constructor {
|
||||||
|
@ -1628,16 +1607,15 @@ impl<'tcx> Usefulness<'tcx> {
|
||||||
|
|
||||||
fn apply_constructor<'p>(
|
fn apply_constructor<'p>(
|
||||||
self,
|
self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
ctor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
UsefulWithWitness(witnesses) => UsefulWithWitness(
|
UsefulWithWitness(witnesses) => UsefulWithWitness(
|
||||||
witnesses
|
witnesses
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|witness| witness.apply_constructor(cx, &ctor, ty, ctor_wild_subpatterns))
|
.map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
x => x,
|
x => x,
|
||||||
|
@ -1646,13 +1624,12 @@ impl<'tcx> Usefulness<'tcx> {
|
||||||
|
|
||||||
fn apply_wildcard<'p>(
|
fn apply_wildcard<'p>(
|
||||||
self,
|
self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
pcx: PatCtxt<'tcx>,
|
|
||||||
missing_ctors: MissingConstructors<'tcx>,
|
missing_ctors: MissingConstructors<'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
UsefulWithWitness(witnesses) => {
|
UsefulWithWitness(witnesses) => {
|
||||||
let new_patterns = missing_ctors.report_patterns(cx, pcx);
|
let new_patterns = missing_ctors.report_patterns(pcx);
|
||||||
UsefulWithWitness(
|
UsefulWithWitness(
|
||||||
witnesses
|
witnesses
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1677,9 +1654,14 @@ crate enum WitnessPreference {
|
||||||
LeaveOutWitness,
|
LeaveOutWitness,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone)]
|
||||||
struct PatCtxt<'tcx> {
|
struct PatCtxt<'a, 'p, 'tcx> {
|
||||||
|
cx: &'a MatchCheckCtxt<'p, 'tcx>,
|
||||||
|
/// Current state of the matrix.
|
||||||
|
matrix: &'a Matrix<'p, 'tcx>,
|
||||||
|
/// Type of the current column under investigation.
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
/// Span of the current pattern under investigation.
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1740,17 +1722,16 @@ impl<'tcx> Witness<'tcx> {
|
||||||
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
|
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
|
||||||
fn apply_constructor<'p>(
|
fn apply_constructor<'p>(
|
||||||
mut self,
|
mut self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
ctor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let pat = {
|
let pat = {
|
||||||
let len = self.0.len();
|
let len = self.0.len();
|
||||||
let arity = ctor_wild_subpatterns.len();
|
let arity = ctor_wild_subpatterns.len();
|
||||||
let pats = self.0.drain((len - arity)..).rev();
|
let pats = self.0.drain((len - arity)..).rev();
|
||||||
let fields = ctor_wild_subpatterns.replace_fields(cx, pats);
|
let fields = ctor_wild_subpatterns.replace_fields(pcx.cx, pats);
|
||||||
ctor.apply(cx, ty, fields)
|
ctor.apply(pcx, fields)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.0.push(pat);
|
self.0.push(pat);
|
||||||
|
@ -1768,11 +1749,9 @@ impl<'tcx> Witness<'tcx> {
|
||||||
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
|
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
|
||||||
/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
|
/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
|
||||||
/// `cx.is_uninhabited()`).
|
/// `cx.is_uninhabited()`).
|
||||||
fn all_constructors<'a, 'tcx>(
|
fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tcx>> {
|
||||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
|
||||||
pcx: PatCtxt<'tcx>,
|
|
||||||
) -> Vec<Constructor<'tcx>> {
|
|
||||||
debug!("all_constructors({:?})", pcx.ty);
|
debug!("all_constructors({:?})", pcx.ty);
|
||||||
|
let cx = pcx.cx;
|
||||||
let make_range = |start, end| {
|
let make_range = |start, end| {
|
||||||
IntRange(
|
IntRange(
|
||||||
// `unwrap()` is ok because we know the type is an integer.
|
// `unwrap()` is ok because we know the type is an integer.
|
||||||
|
@ -2122,9 +2101,7 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
/// merging operation depicted above.)
|
/// merging operation depicted above.)
|
||||||
fn split<'p>(
|
fn split<'p>(
|
||||||
&self,
|
&self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
pcx: PatCtxt<'tcx>,
|
|
||||||
matrix: &Matrix<'p, 'tcx>,
|
|
||||||
hir_id: Option<HirId>,
|
hir_id: Option<HirId>,
|
||||||
) -> SmallVec<[Constructor<'tcx>; 1]> {
|
) -> SmallVec<[Constructor<'tcx>; 1]> {
|
||||||
let ty = pcx.ty;
|
let ty = pcx.ty;
|
||||||
|
@ -2152,14 +2129,15 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
// Collect the span and range of all the intersecting ranges to lint on likely
|
// Collect the span and range of all the intersecting ranges to lint on likely
|
||||||
// incorrect range patterns. (#63987)
|
// incorrect range patterns. (#63987)
|
||||||
let mut overlaps = vec![];
|
let mut overlaps = vec![];
|
||||||
let row_len = matrix.patterns.get(0).map(|r| r.len()).unwrap_or(0);
|
let row_len = pcx.matrix.patterns.get(0).map(|r| r.len()).unwrap_or(0);
|
||||||
// `borders` is the set of borders between equivalence classes: each equivalence
|
// `borders` is the set of borders between equivalence classes: each equivalence
|
||||||
// class lies between 2 borders.
|
// class lies between 2 borders.
|
||||||
let row_borders = matrix
|
let row_borders = pcx
|
||||||
.head_ctors(cx)
|
.matrix
|
||||||
|
.head_ctors(pcx.cx)
|
||||||
.filter_map(|ctor| IntRange::from_ctor(ctor))
|
.filter_map(|ctor| IntRange::from_ctor(ctor))
|
||||||
.filter_map(|range| {
|
.filter_map(|range| {
|
||||||
let intersection = self.intersection(cx.tcx, &range);
|
let intersection = self.intersection(pcx.cx.tcx, &range);
|
||||||
let should_lint = self.suspicious_intersection(&range);
|
let should_lint = self.suspicious_intersection(&range);
|
||||||
if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
|
if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
|
||||||
// FIXME: for now, only check for overlapping ranges on simple range
|
// FIXME: for now, only check for overlapping ranges on simple range
|
||||||
|
@ -2179,7 +2157,7 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
let mut borders: Vec<_> = row_borders.chain(self_borders).collect();
|
let mut borders: Vec<_> = row_borders.chain(self_borders).collect();
|
||||||
borders.sort_unstable();
|
borders.sort_unstable();
|
||||||
|
|
||||||
self.lint_overlapping_patterns(cx.tcx, hir_id, ty, overlaps);
|
self.lint_overlapping_patterns(pcx.cx.tcx, hir_id, ty, overlaps);
|
||||||
|
|
||||||
// We're going to iterate through every adjacent pair of borders, making sure that
|
// We're going to iterate through every adjacent pair of borders, making sure that
|
||||||
// each represents an interval of nonnegative length, and convert each such
|
// each represents an interval of nonnegative length, and convert each such
|
||||||
|
@ -2249,15 +2227,10 @@ struct MissingConstructors<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> MissingConstructors<'tcx> {
|
impl<'tcx> MissingConstructors<'tcx> {
|
||||||
fn new<'p>(
|
fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>, is_top_level: bool) -> Self {
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
pcx: PatCtxt<'tcx>,
|
|
||||||
matrix: &Matrix<'p, 'tcx>,
|
|
||||||
is_top_level: bool,
|
|
||||||
) -> Self {
|
|
||||||
let used_ctors: Vec<Constructor<'_>> =
|
let used_ctors: Vec<Constructor<'_>> =
|
||||||
matrix.head_ctors(cx).cloned().filter(|c| !c.is_wildcard()).collect();
|
pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
|
||||||
let all_ctors = all_constructors(cx, pcx);
|
let all_ctors = all_constructors(pcx);
|
||||||
|
|
||||||
MissingConstructors { all_ctors, used_ctors, is_top_level }
|
MissingConstructors { all_ctors, used_ctors, is_top_level }
|
||||||
}
|
}
|
||||||
|
@ -2277,11 +2250,7 @@ impl<'tcx> MissingConstructors<'tcx> {
|
||||||
|
|
||||||
/// List the patterns corresponding to the missing constructors. In some cases, instead of
|
/// List the patterns corresponding to the missing constructors. In some cases, instead of
|
||||||
/// listing all constructors of a given type, we prefer to simply report a wildcard.
|
/// listing all constructors of a given type, we prefer to simply report a wildcard.
|
||||||
fn report_patterns<'p>(
|
fn report_patterns<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Pat<'tcx>; 1]> {
|
||||||
&self,
|
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
pcx: PatCtxt<'tcx>,
|
|
||||||
) -> SmallVec<[Pat<'tcx>; 1]> {
|
|
||||||
// There are 2 ways we can report a witness here.
|
// There are 2 ways we can report a witness here.
|
||||||
// Commonly, we can report all the "free"
|
// Commonly, we can report all the "free"
|
||||||
// constructors as witnesses, e.g., if we have:
|
// constructors as witnesses, e.g., if we have:
|
||||||
|
@ -2321,8 +2290,8 @@ impl<'tcx> MissingConstructors<'tcx> {
|
||||||
// `Option::Some`, we get the pattern `Some(_)`.
|
// `Option::Some`, we get the pattern `Some(_)`.
|
||||||
self.iter()
|
self.iter()
|
||||||
.map(|missing_ctor| {
|
.map(|missing_ctor| {
|
||||||
let fields = Fields::wildcards(cx, &missing_ctor, pcx.ty);
|
let fields = Fields::wildcards(pcx, &missing_ctor);
|
||||||
missing_ctor.apply(cx, pcx.ty, fields)
|
missing_ctor.apply(pcx, fields)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -2440,28 +2409,17 @@ crate 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 { ty, span: v.head().span };
|
let pcx = PatCtxt { cx, matrix, ty, span: v.head().span };
|
||||||
|
|
||||||
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
|
debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
|
||||||
|
|
||||||
let constructor = v.head_ctor(cx);
|
let constructor = v.head_ctor(cx);
|
||||||
let ret = if !constructor.is_wildcard() {
|
let ret = if !constructor.is_wildcard() {
|
||||||
debug!("is_useful - expanding constructor: {:#?}", constructor);
|
debug!("is_useful - expanding constructor: {:#?}", constructor);
|
||||||
constructor
|
constructor
|
||||||
.split(cx, pcx, matrix, Some(hir_id))
|
.split(pcx, Some(hir_id))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| {
|
.map(|c| is_useful_specialized(pcx, v, c, witness_preference, hir_id, is_under_guard))
|
||||||
is_useful_specialized(
|
|
||||||
cx,
|
|
||||||
matrix,
|
|
||||||
v,
|
|
||||||
c,
|
|
||||||
pcx.ty,
|
|
||||||
witness_preference,
|
|
||||||
hir_id,
|
|
||||||
is_under_guard,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.find(|result| result.is_useful())
|
.find(|result| result.is_useful())
|
||||||
.unwrap_or(NotUseful)
|
.unwrap_or(NotUseful)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2478,7 +2436,7 @@ crate fn is_useful<'p, 'tcx>(
|
||||||
// Missing constructors are those that are not matched by any non-wildcard patterns in the
|
// Missing constructors are those that are not matched by any non-wildcard patterns in the
|
||||||
// current column. We only fully construct them on-demand, because they're rarely used and
|
// current column. We only fully construct them on-demand, because they're rarely used and
|
||||||
// can be big.
|
// can be big.
|
||||||
let missing_ctors = MissingConstructors::new(cx, pcx, matrix, is_top_level);
|
let missing_ctors = MissingConstructors::new(pcx, is_top_level);
|
||||||
|
|
||||||
debug!("is_useful_missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
|
debug!("is_useful_missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
|
||||||
|
|
||||||
|
@ -2486,31 +2444,22 @@ crate fn is_useful<'p, 'tcx>(
|
||||||
let (all_ctors, _) = missing_ctors.into_inner();
|
let (all_ctors, _) = missing_ctors.into_inner();
|
||||||
all_ctors
|
all_ctors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|ctor| ctor.split(cx, pcx, matrix, None))
|
.flat_map(|ctor| ctor.split(pcx, None))
|
||||||
.map(|c| {
|
.map(|c| {
|
||||||
is_useful_specialized(
|
is_useful_specialized(pcx, v, c, witness_preference, hir_id, is_under_guard)
|
||||||
cx,
|
|
||||||
matrix,
|
|
||||||
v,
|
|
||||||
c,
|
|
||||||
pcx.ty,
|
|
||||||
witness_preference,
|
|
||||||
hir_id,
|
|
||||||
is_under_guard,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.find(|result| result.is_useful())
|
.find(|result| result.is_useful())
|
||||||
.unwrap_or(NotUseful)
|
.unwrap_or(NotUseful)
|
||||||
} else {
|
} else {
|
||||||
let ctor_wild_subpatterns = Fields::empty();
|
let ctor_wild_subpatterns = Fields::empty();
|
||||||
let matrix = matrix.specialize_constructor(cx, &constructor, &ctor_wild_subpatterns);
|
let matrix = matrix.specialize_constructor(pcx, &constructor, &ctor_wild_subpatterns);
|
||||||
// Unwrap is ok: v can always be specialized with its own constructor.
|
// Unwrap is ok: v can always be specialized with its own constructor.
|
||||||
let v =
|
let v =
|
||||||
v.specialize_constructor(cx, &constructor, &ctor_wild_subpatterns, true).unwrap();
|
v.specialize_constructor(pcx, &constructor, &ctor_wild_subpatterns, true).unwrap();
|
||||||
let usefulness =
|
let usefulness =
|
||||||
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
|
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
|
||||||
|
|
||||||
usefulness.apply_wildcard(cx, pcx, missing_ctors)
|
usefulness.apply_wildcard(pcx, missing_ctors)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
|
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
|
||||||
|
@ -2520,23 +2469,21 @@ crate fn is_useful<'p, 'tcx>(
|
||||||
/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
|
/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
|
||||||
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
|
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
|
||||||
fn is_useful_specialized<'p, 'tcx>(
|
fn is_useful_specialized<'p, 'tcx>(
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
matrix: &Matrix<'p, 'tcx>,
|
|
||||||
v: &PatStack<'p, 'tcx>,
|
v: &PatStack<'p, 'tcx>,
|
||||||
ctor: Constructor<'tcx>,
|
ctor: Constructor<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
witness_preference: WitnessPreference,
|
witness_preference: WitnessPreference,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
is_under_guard: bool,
|
is_under_guard: bool,
|
||||||
) -> Usefulness<'tcx> {
|
) -> Usefulness<'tcx> {
|
||||||
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, ty);
|
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, pcx.ty);
|
||||||
|
|
||||||
// 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(cx, &ctor, ty);
|
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
|
||||||
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
|
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
|
||||||
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns, true)
|
v.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns, true)
|
||||||
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
|
.map(|v| is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
|
||||||
.map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns))
|
.map(|u| u.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns))
|
||||||
.unwrap_or(NotUseful)
|
.unwrap_or(NotUseful)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue