1
Fork 0

Pass more things through PatCtxt

This is even a perf improvement on the match-heavy benchmarks.
This commit is contained in:
Nadrieril 2020-10-26 18:13:30 +00:00
parent cdafd1e1bd
commit b49f90760d

View file

@ -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)
} }