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::fmt;
|
|
|
|
|
|
|
|
use smallvec::{smallvec, SmallVec};
|
|
|
|
|
2023-12-11 10:11:12 +00:00
|
|
|
use crate::constructor::{Constructor, Slice, SliceKind};
|
2024-02-28 16:56:01 +00:00
|
|
|
use crate::{PrivateUninhabitedField, TypeCx};
|
2023-12-11 19:59:32 +00:00
|
|
|
|
|
|
|
use self::Constructor::*;
|
2023-12-10 19:42:30 +00:00
|
|
|
|
2024-02-07 17:59:40 +00:00
|
|
|
/// A globally unique id to distinguish patterns.
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub(crate) struct PatId(u32);
|
|
|
|
impl PatId {
|
|
|
|
fn new() -> Self {
|
|
|
|
use std::sync::atomic::{AtomicU32, Ordering};
|
|
|
|
static PAT_ID: AtomicU32 = AtomicU32::new(0);
|
|
|
|
PatId(PAT_ID.fetch_add(1, Ordering::SeqCst))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-29 22:34:57 +00:00
|
|
|
/// A pattern with an index denoting which field it corresponds to.
|
|
|
|
pub struct IndexedPat<Cx: TypeCx> {
|
|
|
|
pub idx: usize,
|
|
|
|
pub pat: DeconstructedPat<Cx>,
|
|
|
|
}
|
|
|
|
|
2023-12-10 19:42:30 +00:00
|
|
|
/// Values and patterns can be represented as a constructor applied to some fields. This represents
|
2024-01-24 22:23:14 +00:00
|
|
|
/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
|
|
|
|
/// exception are some `Wildcard`s introduced during pattern lowering.
|
2024-01-25 02:37:24 +00:00
|
|
|
pub struct DeconstructedPat<Cx: TypeCx> {
|
2023-12-11 19:01:02 +00:00
|
|
|
ctor: Constructor<Cx>,
|
2024-02-29 22:34:57 +00:00
|
|
|
fields: Vec<IndexedPat<Cx>>,
|
2024-02-29 22:34:52 +00:00
|
|
|
/// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
|
|
|
|
/// }` this would be the total number of fields of the struct.
|
|
|
|
/// This is also the same as `self.ctor.arity(self.ty)`.
|
|
|
|
arity: usize,
|
2023-12-11 19:01:02 +00:00
|
|
|
ty: Cx::Ty,
|
2024-02-06 02:37:03 +00:00
|
|
|
/// Extra data to store in a pattern.
|
|
|
|
data: Cx::PatData,
|
2024-02-07 17:59:40 +00:00
|
|
|
/// Globally-unique id used to track usefulness at the level of subpatterns.
|
|
|
|
pub(crate) uid: PatId,
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-25 02:37:24 +00:00
|
|
|
impl<Cx: TypeCx> DeconstructedPat<Cx> {
|
2023-12-11 09:56:21 +00:00
|
|
|
pub fn new(
|
2023-12-11 19:01:02 +00:00
|
|
|
ctor: Constructor<Cx>,
|
2024-02-29 22:34:57 +00:00
|
|
|
fields: Vec<IndexedPat<Cx>>,
|
2024-02-29 22:34:52 +00:00
|
|
|
arity: usize,
|
2023-12-11 19:01:02 +00:00
|
|
|
ty: Cx::Ty,
|
2023-12-15 15:18:21 +00:00
|
|
|
data: Cx::PatData,
|
2023-12-10 19:42:30 +00:00
|
|
|
) -> Self {
|
2024-02-06 02:37:03 +00:00
|
|
|
DeconstructedPat { ctor, fields, arity, ty, data, uid: PatId::new() }
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2024-02-29 22:34:57 +00:00
|
|
|
pub fn at_index(self, idx: usize) -> IndexedPat<Cx> {
|
|
|
|
IndexedPat { idx, pat: self }
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
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-22 23:21:27 +00:00
|
|
|
pub fn ty(&self) -> &Cx::Ty {
|
|
|
|
&self.ty
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
2024-02-06 02:37:03 +00:00
|
|
|
/// Returns the extra data stored in a pattern.
|
|
|
|
pub fn data(&self) -> &Cx::PatData {
|
|
|
|
&self.data
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
2024-02-29 22:34:57 +00:00
|
|
|
pub fn arity(&self) -> usize {
|
|
|
|
self.arity
|
|
|
|
}
|
2023-12-10 19:42:30 +00:00
|
|
|
|
2024-02-29 22:34:57 +00:00
|
|
|
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a IndexedPat<Cx>> {
|
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.
|
2024-01-25 02:37:24 +00:00
|
|
|
pub(crate) fn specialize<'a>(
|
|
|
|
&'a self,
|
2023-12-11 19:01:02 +00:00
|
|
|
other_ctor: &Constructor<Cx>,
|
2024-02-29 22:34:57 +00:00
|
|
|
other_ctor_arity: usize,
|
2024-01-25 02:37:24 +00:00
|
|
|
) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
|
2024-02-29 22:34:57 +00:00
|
|
|
if matches!(other_ctor, PrivateUninhabited) {
|
2024-02-06 01:53:37 +00:00
|
|
|
// Skip this column.
|
2024-02-29 22:34:57 +00:00
|
|
|
return smallvec![];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start with a slice of wildcards of the appropriate length.
|
|
|
|
let mut fields: SmallVec<[_; 2]> = (0..other_ctor_arity).map(|_| PatOrWild::Wild).collect();
|
|
|
|
// Fill `fields` with our fields. The arities are known to be compatible.
|
|
|
|
match self.ctor {
|
|
|
|
// The only non-trivial case: two slices of different arity. `other_ctor` is guaranteed
|
|
|
|
// to have a larger arity, so we adjust the indices of the patterns in the suffix so
|
|
|
|
// that they are correctly positioned in the larger slice.
|
|
|
|
Slice(Slice { kind: SliceKind::VarLen(prefix, _), .. })
|
|
|
|
if self.arity != other_ctor_arity =>
|
|
|
|
{
|
|
|
|
for ipat in &self.fields {
|
|
|
|
let new_idx = if ipat.idx < prefix {
|
|
|
|
ipat.idx
|
|
|
|
} else {
|
|
|
|
// Adjust the indices in the suffix.
|
|
|
|
ipat.idx + other_ctor_arity - self.arity
|
|
|
|
};
|
|
|
|
fields[new_idx] = PatOrWild::Pat(&ipat.pat);
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
2024-02-29 22:34:57 +00:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
for ipat in &self.fields {
|
|
|
|
fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
|
2023-12-11 10:11:12 +00:00
|
|
|
}
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
2024-02-29 22:34:57 +00:00
|
|
|
fields
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-24 22:08:36 +00:00
|
|
|
/// Walk top-down and call `it` in each place where a pattern occurs
|
|
|
|
/// starting with the root pattern `walk` is called on. If `it` returns
|
|
|
|
/// false then we will descend no further but siblings will be processed.
|
|
|
|
pub fn walk<'a>(&'a self, it: &mut impl FnMut(&'a Self) -> bool) {
|
|
|
|
if !it(self) {
|
|
|
|
return;
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-24 22:08:36 +00:00
|
|
|
for p in self.iter_fields() {
|
2024-02-29 22:34:57 +00:00
|
|
|
p.pat.walk(it)
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-07 10:03:40 +00:00
|
|
|
/// This is best effort and not good enough for a `Display` impl.
|
2024-01-25 02:37:24 +00:00
|
|
|
impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
|
2023-12-10 19:42:30 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2024-01-24 19:04:33 +00:00
|
|
|
let pat = self;
|
|
|
|
let mut first = true;
|
|
|
|
let mut start_or_continue = |s| {
|
|
|
|
if first {
|
|
|
|
first = false;
|
|
|
|
""
|
|
|
|
} else {
|
|
|
|
s
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let mut start_or_comma = || start_or_continue(", ");
|
|
|
|
|
2024-02-29 22:34:57 +00:00
|
|
|
let mut fields: Vec<_> = (0..self.arity).map(|_| PatOrWild::Wild).collect();
|
|
|
|
for ipat in self.iter_fields() {
|
|
|
|
fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
|
|
|
|
}
|
|
|
|
|
2024-01-24 19:04:33 +00:00
|
|
|
match pat.ctor() {
|
|
|
|
Struct | Variant(_) | UnionField => {
|
|
|
|
Cx::write_variant_name(f, pat)?;
|
|
|
|
// Without `cx`, we can't know which field corresponds to which, so we can't
|
|
|
|
// get the names of the fields. Instead we just display everything as a tuple
|
|
|
|
// struct, which should be good enough.
|
|
|
|
write!(f, "(")?;
|
2024-02-29 22:34:57 +00:00
|
|
|
for p in fields {
|
2024-01-24 19:04:33 +00:00
|
|
|
write!(f, "{}", start_or_comma())?;
|
|
|
|
write!(f, "{p:?}")?;
|
|
|
|
}
|
|
|
|
write!(f, ")")
|
|
|
|
}
|
|
|
|
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
|
|
|
// be careful to detect strings here. However a string literal pattern will never
|
|
|
|
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
|
|
|
Ref => {
|
2024-02-29 22:34:57 +00:00
|
|
|
write!(f, "&{:?}", &fields[0])
|
2024-01-24 19:04:33 +00:00
|
|
|
}
|
|
|
|
Slice(slice) => {
|
|
|
|
write!(f, "[")?;
|
|
|
|
match slice.kind {
|
|
|
|
SliceKind::FixedLen(_) => {
|
2024-02-29 22:34:57 +00:00
|
|
|
for p in fields {
|
2024-01-24 19:04:33 +00:00
|
|
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SliceKind::VarLen(prefix_len, _) => {
|
2024-02-29 22:34:57 +00:00
|
|
|
for p in &fields[..prefix_len] {
|
2024-01-24 19:04:33 +00:00
|
|
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
|
|
}
|
|
|
|
write!(f, "{}", start_or_comma())?;
|
|
|
|
write!(f, "..")?;
|
2024-02-29 22:34:57 +00:00
|
|
|
for p in &fields[prefix_len..] {
|
2024-01-24 19:04:33 +00:00
|
|
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
write!(f, "]")
|
|
|
|
}
|
|
|
|
Bool(b) => write!(f, "{b}"),
|
|
|
|
// Best-effort, will render signed ranges incorrectly
|
|
|
|
IntRange(range) => write!(f, "{range:?}"),
|
|
|
|
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
|
|
|
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
|
|
|
Str(value) => write!(f, "{value:?}"),
|
|
|
|
Opaque(..) => write!(f, "<constant pattern>"),
|
|
|
|
Or => {
|
2024-02-29 22:34:57 +00:00
|
|
|
for pat in fields {
|
2024-01-24 19:04:33 +00:00
|
|
|
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-02-28 16:56:01 +00:00
|
|
|
Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
|
|
|
|
write!(f, "_ : {:?}", pat.ty())
|
|
|
|
}
|
2024-01-24 19:04:33 +00:00
|
|
|
}
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-07 10:03:40 +00:00
|
|
|
/// Represents either a pattern obtained from user input or a wildcard constructed during the
|
|
|
|
/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
|
|
|
|
///
|
|
|
|
/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
|
|
|
|
pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
|
|
|
|
/// A non-user-provided wildcard, created during specialization.
|
|
|
|
Wild,
|
|
|
|
/// A user-provided pattern.
|
2024-01-25 02:37:24 +00:00
|
|
|
Pat(&'p DeconstructedPat<Cx>),
|
2024-01-07 10:03:40 +00:00
|
|
|
}
|
|
|
|
|
2024-01-27 12:18:33 +00:00
|
|
|
impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
match self {
|
|
|
|
PatOrWild::Wild => PatOrWild::Wild,
|
|
|
|
PatOrWild::Pat(pat) => PatOrWild::Pat(pat),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {}
|
|
|
|
|
2024-01-07 10:03:40 +00:00
|
|
|
impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
|
2024-01-25 02:37:24 +00:00
|
|
|
pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
|
2024-01-07 10:03:40 +00:00
|
|
|
match self {
|
2024-01-09 15:22:11 +00:00
|
|
|
PatOrWild::Wild => None,
|
|
|
|
PatOrWild::Pat(pat) => Some(pat),
|
2024-01-07 10:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub(crate) fn ctor(self) -> &'p Constructor<Cx> {
|
|
|
|
match self {
|
2024-01-09 15:22:11 +00:00
|
|
|
PatOrWild::Wild => &Wildcard,
|
|
|
|
PatOrWild::Pat(pat) => pat.ctor(),
|
2024-01-07 10:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn is_or_pat(&self) -> bool {
|
|
|
|
match self {
|
2024-01-09 15:22:11 +00:00
|
|
|
PatOrWild::Wild => false,
|
|
|
|
PatOrWild::Pat(pat) => pat.is_or_pat(),
|
2024-01-07 10:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Expand this (possibly-nested) or-pattern into its alternatives.
|
|
|
|
pub(crate) fn flatten_or_pat(self) -> SmallVec<[Self; 1]> {
|
|
|
|
match self {
|
2024-02-29 22:34:57 +00:00
|
|
|
PatOrWild::Pat(pat) if pat.is_or_pat() => pat
|
|
|
|
.iter_fields()
|
|
|
|
.flat_map(|ipat| PatOrWild::Pat(&ipat.pat).flatten_or_pat())
|
|
|
|
.collect(),
|
2024-01-07 10:03:40 +00:00
|
|
|
_ => smallvec![self],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Specialize this pattern with a constructor.
|
|
|
|
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
|
|
|
|
pub(crate) fn specialize(
|
|
|
|
&self,
|
|
|
|
other_ctor: &Constructor<Cx>,
|
2024-01-03 00:25:32 +00:00
|
|
|
ctor_arity: usize,
|
2024-01-07 10:03:40 +00:00
|
|
|
) -> SmallVec<[PatOrWild<'p, Cx>; 2]> {
|
|
|
|
match self {
|
2024-01-09 15:22:11 +00:00
|
|
|
PatOrWild::Wild => (0..ctor_arity).map(|_| PatOrWild::Wild).collect(),
|
|
|
|
PatOrWild::Pat(pat) => pat.specialize(other_ctor, ctor_arity),
|
2024-01-07 10:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
2024-01-09 15:22:11 +00:00
|
|
|
PatOrWild::Wild => write!(f, "_"),
|
|
|
|
PatOrWild::Pat(pat) => pat.fmt(f),
|
2024-01-07 10:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2024-01-31 00:29:21 +00:00
|
|
|
#[derive(Debug)]
|
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
|
|
|
}
|
|
|
|
|
2024-01-27 12:18:33 +00:00
|
|
|
impl<Cx: TypeCx> Clone for WitnessPat<Cx> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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(_)`.
|
2024-01-24 20:16:57 +00:00
|
|
|
pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self {
|
2024-02-06 01:44:48 +00:00
|
|
|
let fields = cx
|
|
|
|
.ctor_sub_tys(&ctor, &ty)
|
2024-02-28 16:56:01 +00:00
|
|
|
.filter(|(_, PrivateUninhabitedField(skip))| !skip)
|
2024-02-06 01:44:48 +00:00
|
|
|
.map(|(ty, _)| Self::wildcard(ty))
|
|
|
|
.collect();
|
2024-01-24 20:16:57 +00:00
|
|
|
Self::new(ctor, fields, ty)
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
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-22 23:21:27 +00:00
|
|
|
pub fn ty(&self) -> &Cx::Ty {
|
|
|
|
&self.ty
|
2023-12-10 19:42:30 +00:00
|
|
|
}
|
|
|
|
|
2023-12-26 02:06:39 +00:00
|
|
|
pub fn iter_fields(&self) -> impl Iterator<Item = &WitnessPat<Cx>> {
|
2023-12-10 19:42:30 +00:00
|
|
|
self.fields.iter()
|
|
|
|
}
|
|
|
|
}
|