2023-12-10 19:42:30 +00:00
|
|
|
//! As explained in [`crate::usefulness`], values and patterns are made from constructors applied to
|
|
|
|
//! fields. This file defines types that represent patterns in this way.
|
|
|
|
use std::cell::Cell;
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
use smallvec::{smallvec, SmallVec};
|
|
|
|
|
2023-12-11 10:11:12 +00:00
|
|
|
use crate::constructor::{Constructor, Slice, SliceKind};
|
2023-12-15 15:32:44 +00:00
|
|
|
use crate::usefulness::PlaceCtxt;
|
2023-12-15 16:25:11 +00:00
|
|
|
use crate::{Captures, TypeCx};
|
2023-12-11 19:59:32 +00:00
|
|
|
|
|
|
|
use self::Constructor::*;
|
2023-12-10 19:42:30 +00:00
|
|
|
|
|
|
|
/// Values and patterns can be represented as a constructor applied to some fields. This represents
|
|
|
|
/// a pattern in this form.
|
|
|
|
/// This also uses interior mutability to keep track of whether the pattern has been found reachable
|
|
|
|
/// during analysis. For this reason they cannot be cloned.
|
|
|
|
/// A `DeconstructedPat` will almost always come from user input; the only exception are some
|
|
|
|
/// `Wildcard`s introduced during specialization.
|
2023-12-10 21:14:00 +00:00
|
|
|
///
|
|
|
|
/// Note that the number of fields may not match the fields declared in the original struct/variant.
|
|
|
|
/// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't
|
|
|
|
/// observe that it is uninhabited. In that case that field is not included in `fields`. Care must
|
|
|
|
/// be taken when converting to/from `thir::Pat`.
|
2023-12-15 16:25:11 +00:00
|
|
|
pub struct DeconstructedPat<'p, Cx: TypeCx> {
|
2023-12-11 19:01:02 +00:00
|
|
|
ctor: Constructor<Cx>,
|
|
|
|
fields: &'p [DeconstructedPat<'p, Cx>],
|
|
|
|
ty: Cx::Ty,
|
2023-12-15 15:18:21 +00:00
|
|
|
data: Cx::PatData,
|
2023-12-10 19:42:30 +00:00
|
|
|
/// Whether removing this arm would change the behavior of the match expression.
|
|
|
|
useful: Cell<bool>,
|
|
|
|
}
|
|
|
|
|
2023-12-15 16:25:11 +00:00
|
|
|
impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
|
2023-12-15 15:18:21 +00:00
|
|
|
pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self {
|
|
|
|
Self::new(Wildcard, &[], ty, data)
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2023-12-11 09:56:21 +00:00
|
|
|
pub fn new(
|
2023-12-11 19:01:02 +00:00
|
|
|
ctor: Constructor<Cx>,
|
|
|
|
fields: &'p [DeconstructedPat<'p, Cx>],
|
|
|
|
ty: Cx::Ty,
|
2023-12-15 15:18:21 +00:00
|
|
|
data: Cx::PatData,
|
2023-12-10 19:42:30 +00:00
|
|
|
) -> Self {
|
2023-12-15 15:18:21 +00:00
|
|
|
DeconstructedPat { ctor, fields, ty, data, useful: Cell::new(false) }
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2023-12-11 09:56:21 +00:00
|
|
|
pub(crate) fn is_or_pat(&self) -> bool {
|
2023-12-10 19:42:30 +00:00
|
|
|
matches!(self.ctor, Or)
|
|
|
|
}
|
|
|
|
/// Expand this (possibly-nested) or-pattern into its alternatives.
|
2023-12-11 16:57:53 +00:00
|
|
|
pub(crate) fn flatten_or_pat(&self) -> SmallVec<[&Self; 1]> {
|
2023-12-10 19:42:30 +00:00
|
|
|
if self.is_or_pat() {
|
|
|
|
self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect()
|
|
|
|
} else {
|
|
|
|
smallvec![self]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-11 19:01:02 +00:00
|
|
|
pub fn ctor(&self) -> &Constructor<Cx> {
|
2023-12-10 19:42:30 +00:00
|
|
|
&self.ctor
|
|
|
|
}
|
2023-12-11 19:01:02 +00:00
|
|
|
pub fn ty(&self) -> Cx::Ty {
|
2023-12-10 19:42:30 +00:00
|
|
|
self.ty
|
|
|
|
}
|
2023-12-15 15:18:21 +00:00
|
|
|
pub fn data(&self) -> &Cx::PatData {
|
|
|
|
&self.data
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn iter_fields<'a>(
|
|
|
|
&'a self,
|
2023-12-11 19:01:02 +00:00
|
|
|
) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
|
2023-12-10 21:14:00 +00:00
|
|
|
self.fields.iter()
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Specialize this pattern with a constructor.
|
|
|
|
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
|
2023-12-11 09:56:21 +00:00
|
|
|
pub(crate) fn specialize<'a>(
|
2023-12-11 16:57:53 +00:00
|
|
|
&self,
|
2023-12-15 15:32:44 +00:00
|
|
|
pcx: &PlaceCtxt<'a, 'p, Cx>,
|
2023-12-11 19:01:02 +00:00
|
|
|
other_ctor: &Constructor<Cx>,
|
|
|
|
) -> SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]> {
|
2023-12-11 16:57:53 +00:00
|
|
|
let wildcard_sub_tys = || {
|
2023-12-15 15:53:29 +00:00
|
|
|
let tys = pcx.ctor_sub_tys(other_ctor);
|
2023-12-11 16:57:53 +00:00
|
|
|
tys.iter()
|
2023-12-15 15:18:21 +00:00
|
|
|
.map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default()))
|
2023-12-15 15:53:29 +00:00
|
|
|
.map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
|
2023-12-11 16:57:53 +00:00
|
|
|
.collect()
|
|
|
|
};
|
2023-12-10 19:42:30 +00:00
|
|
|
match (&self.ctor, other_ctor) {
|
2023-12-11 16:57:53 +00:00
|
|
|
// Return a wildcard for each field of `other_ctor`.
|
|
|
|
(Wildcard, _) => wildcard_sub_tys(),
|
|
|
|
// The only non-trivial case: two slices of different arity. `other_slice` is
|
|
|
|
// guaranteed to have a larger arity, so we fill the middle part with enough
|
|
|
|
// wildcards to reach the length of the new, larger slice.
|
2023-12-11 10:11:12 +00:00
|
|
|
(
|
|
|
|
&Slice(self_slice @ Slice { kind: SliceKind::VarLen(prefix, suffix), .. }),
|
|
|
|
&Slice(other_slice),
|
|
|
|
) if self_slice.arity() != other_slice.arity() => {
|
|
|
|
// Start with a slice of wildcards of the appropriate length.
|
2023-12-11 16:57:53 +00:00
|
|
|
let mut fields: SmallVec<[_; 2]> = wildcard_sub_tys();
|
2023-12-11 10:11:12 +00:00
|
|
|
// Fill in the fields from both ends.
|
|
|
|
let new_arity = fields.len();
|
|
|
|
for i in 0..prefix {
|
|
|
|
fields[i] = &self.fields[i];
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
2023-12-11 10:11:12 +00:00
|
|
|
for i in 0..suffix {
|
|
|
|
fields[new_arity - 1 - i] = &self.fields[self.fields.len() - 1 - i];
|
|
|
|
}
|
|
|
|
fields
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
2023-12-10 21:14:00 +00:00
|
|
|
_ => self.fields.iter().collect(),
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-15 15:18:21 +00:00
|
|
|
/// We keep track for each pattern if it was ever useful during the analysis. This is used with
|
|
|
|
/// `redundant_subpatterns` to report redundant subpatterns arising from or patterns.
|
2023-12-11 09:56:21 +00:00
|
|
|
pub(crate) fn set_useful(&self) {
|
2023-12-10 19:42:30 +00:00
|
|
|
self.useful.set(true)
|
|
|
|
}
|
2023-12-11 09:56:21 +00:00
|
|
|
pub(crate) fn is_useful(&self) -> bool {
|
2023-12-10 19:42:30 +00:00
|
|
|
if self.useful.get() {
|
|
|
|
true
|
|
|
|
} else if self.is_or_pat() && self.iter_fields().any(|f| f.is_useful()) {
|
|
|
|
// We always expand or patterns in the matrix, so we will never see the actual
|
|
|
|
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
|
|
|
|
// marked as useful itself, only its children will. We recover this information here.
|
|
|
|
self.set_useful();
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-15 15:18:21 +00:00
|
|
|
/// Report the subpatterns that were not useful, if any.
|
|
|
|
pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
|
|
|
|
let mut subpats = Vec::new();
|
|
|
|
self.collect_redundant_subpatterns(&mut subpats);
|
|
|
|
subpats
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
2023-12-15 15:18:21 +00:00
|
|
|
fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
|
2023-12-10 19:42:30 +00:00
|
|
|
// We don't look at subpatterns if we already reported the whole pattern as redundant.
|
|
|
|
if !self.is_useful() {
|
2023-12-15 15:18:21 +00:00
|
|
|
subpats.push(self);
|
2023-12-10 19:42:30 +00:00
|
|
|
} else {
|
|
|
|
for p in self.iter_fields() {
|
2023-12-15 15:18:21 +00:00
|
|
|
p.collect_redundant_subpatterns(subpats);
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
|
|
|
|
/// `Display` impl.
|
2023-12-15 16:25:11 +00:00
|
|
|
impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
|
2023-12-10 19:42:30 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2023-12-11 19:01:02 +00:00
|
|
|
Cx::debug_pat(f, self)
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
|
|
|
|
/// purposes. As such they don't use interning and can be cloned.
|
2023-12-19 17:09:31 +00:00
|
|
|
#[derive(derivative::Derivative)]
|
|
|
|
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
2023-12-15 16:25:11 +00:00
|
|
|
pub struct WitnessPat<Cx: TypeCx> {
|
2023-12-11 19:01:02 +00:00
|
|
|
ctor: Constructor<Cx>,
|
|
|
|
pub(crate) fields: Vec<WitnessPat<Cx>>,
|
|
|
|
ty: Cx::Ty,
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2023-12-15 16:25:11 +00:00
|
|
|
impl<Cx: TypeCx> WitnessPat<Cx> {
|
2023-12-11 19:01:02 +00:00
|
|
|
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
|
2023-12-10 19:42:30 +00:00
|
|
|
Self { ctor, fields, ty }
|
|
|
|
}
|
2023-12-11 19:01:02 +00:00
|
|
|
pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
|
2023-12-10 19:42:30 +00:00
|
|
|
Self::new(Wildcard, Vec::new(), ty)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Construct a pattern that matches everything that starts with this constructor.
|
|
|
|
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
|
|
|
|
/// `Some(_)`.
|
2023-12-15 15:32:44 +00:00
|
|
|
pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, '_, Cx>, ctor: Constructor<Cx>) -> Self {
|
2023-12-15 15:53:29 +00:00
|
|
|
let field_tys = pcx.ctor_sub_tys(&ctor);
|
2023-12-11 16:57:53 +00:00
|
|
|
let fields = field_tys.iter().map(|ty| Self::wildcard(*ty)).collect();
|
2023-12-10 19:42:30 +00:00
|
|
|
Self::new(ctor, fields, pcx.ty)
|
|
|
|
}
|
|
|
|
|
2023-12-11 19:01:02 +00:00
|
|
|
pub fn ctor(&self) -> &Constructor<Cx> {
|
2023-12-10 19:42:30 +00:00
|
|
|
&self.ctor
|
|
|
|
}
|
2023-12-11 19:01:02 +00:00
|
|
|
pub fn ty(&self) -> Cx::Ty {
|
2023-12-10 19:42:30 +00:00
|
|
|
self.ty
|
|
|
|
}
|
|
|
|
|
2023-12-11 19:01:02 +00:00
|
|
|
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a WitnessPat<Cx>> {
|
2023-12-10 19:42:30 +00:00
|
|
|
self.fields.iter()
|
|
|
|
}
|
|
|
|
}
|