rustc_pattern_analysis/
pat.rs

1//! As explained in [`crate::usefulness`], values and patterns are made from constructors applied to
2//! fields. This file defines types that represent patterns in this way.
3
4use std::fmt;
5
6use smallvec::{SmallVec, smallvec};
7
8use self::Constructor::*;
9use crate::constructor::{Constructor, Slice, SliceKind};
10use crate::{PatCx, PrivateUninhabitedField};
11
12/// A globally unique id to distinguish patterns.
13#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub(crate) struct PatId(u32);
15impl PatId {
16    fn new() -> Self {
17        use std::sync::atomic::{AtomicU32, Ordering};
18        static PAT_ID: AtomicU32 = AtomicU32::new(0);
19        PatId(PAT_ID.fetch_add(1, Ordering::SeqCst))
20    }
21}
22
23/// A pattern with an index denoting which field it corresponds to.
24pub struct IndexedPat<Cx: PatCx> {
25    pub idx: usize,
26    pub pat: DeconstructedPat<Cx>,
27}
28
29/// Values and patterns can be represented as a constructor applied to some fields. This represents
30/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
31/// exception are some `Wildcard`s introduced during pattern lowering.
32pub struct DeconstructedPat<Cx: PatCx> {
33    ctor: Constructor<Cx>,
34    fields: Vec<IndexedPat<Cx>>,
35    /// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
36    /// }` this would be the total number of fields of the struct.
37    /// This is also the same as `self.ctor.arity(self.ty)`.
38    arity: usize,
39    ty: Cx::Ty,
40    /// Extra data to store in a pattern.
41    data: Cx::PatData,
42    /// Globally-unique id used to track usefulness at the level of subpatterns.
43    pub(crate) uid: PatId,
44}
45
46impl<Cx: PatCx> DeconstructedPat<Cx> {
47    pub fn new(
48        ctor: Constructor<Cx>,
49        fields: Vec<IndexedPat<Cx>>,
50        arity: usize,
51        ty: Cx::Ty,
52        data: Cx::PatData,
53    ) -> Self {
54        DeconstructedPat { ctor, fields, arity, ty, data, uid: PatId::new() }
55    }
56
57    pub fn at_index(self, idx: usize) -> IndexedPat<Cx> {
58        IndexedPat { idx, pat: self }
59    }
60
61    pub(crate) fn is_or_pat(&self) -> bool {
62        matches!(self.ctor, Or)
63    }
64
65    pub fn ctor(&self) -> &Constructor<Cx> {
66        &self.ctor
67    }
68    pub fn ty(&self) -> &Cx::Ty {
69        &self.ty
70    }
71    /// Returns the extra data stored in a pattern.
72    pub fn data(&self) -> &Cx::PatData {
73        &self.data
74    }
75    pub fn arity(&self) -> usize {
76        self.arity
77    }
78
79    pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a IndexedPat<Cx>> {
80        self.fields.iter()
81    }
82
83    /// Specialize this pattern with a constructor.
84    /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
85    pub(crate) fn specialize<'a>(
86        &'a self,
87        other_ctor: &Constructor<Cx>,
88        other_ctor_arity: usize,
89    ) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
90        if matches!(other_ctor, PrivateUninhabited) {
91            // Skip this column.
92            return smallvec![];
93        }
94
95        // Start with a slice of wildcards of the appropriate length.
96        let mut fields: SmallVec<[_; 2]> = (0..other_ctor_arity).map(|_| PatOrWild::Wild).collect();
97        // Fill `fields` with our fields. The arities are known to be compatible.
98        match self.ctor {
99            // The only non-trivial case: two slices of different arity. `other_ctor` is guaranteed
100            // to have a larger arity, so we adjust the indices of the patterns in the suffix so
101            // that they are correctly positioned in the larger slice.
102            Slice(Slice { kind: SliceKind::VarLen(prefix, _), .. })
103                if self.arity != other_ctor_arity =>
104            {
105                for ipat in &self.fields {
106                    let new_idx = if ipat.idx < prefix {
107                        ipat.idx
108                    } else {
109                        // Adjust the indices in the suffix.
110                        ipat.idx + other_ctor_arity - self.arity
111                    };
112                    fields[new_idx] = PatOrWild::Pat(&ipat.pat);
113                }
114            }
115            _ => {
116                for ipat in &self.fields {
117                    fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
118                }
119            }
120        }
121        fields
122    }
123
124    /// Walk top-down and call `it` in each place where a pattern occurs
125    /// starting with the root pattern `walk` is called on. If `it` returns
126    /// false then we will descend no further but siblings will be processed.
127    pub fn walk<'a>(&'a self, it: &mut impl FnMut(&'a Self) -> bool) {
128        if !it(self) {
129            return;
130        }
131
132        for p in self.iter_fields() {
133            p.pat.walk(it)
134        }
135    }
136}
137
138/// This is best effort and not good enough for a `Display` impl.
139impl<Cx: PatCx> fmt::Debug for DeconstructedPat<Cx> {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        let mut fields: Vec<_> = (0..self.arity).map(|_| PatOrWild::Wild).collect();
142        for ipat in self.iter_fields() {
143            fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
144        }
145        self.ctor().fmt_fields(f, self.ty(), fields.into_iter())
146    }
147}
148
149/// Delegate to `uid`.
150impl<Cx: PatCx> PartialEq for DeconstructedPat<Cx> {
151    fn eq(&self, other: &Self) -> bool {
152        self.uid == other.uid
153    }
154}
155/// Delegate to `uid`.
156impl<Cx: PatCx> Eq for DeconstructedPat<Cx> {}
157/// Delegate to `uid`.
158impl<Cx: PatCx> std::hash::Hash for DeconstructedPat<Cx> {
159    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
160        self.uid.hash(state);
161    }
162}
163
164/// Represents either a pattern obtained from user input or a wildcard constructed during the
165/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
166///
167/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
168pub(crate) enum PatOrWild<'p, Cx: PatCx> {
169    /// A non-user-provided wildcard, created during specialization.
170    Wild,
171    /// A user-provided pattern.
172    Pat(&'p DeconstructedPat<Cx>),
173}
174
175impl<'p, Cx: PatCx> Clone for PatOrWild<'p, Cx> {
176    fn clone(&self) -> Self {
177        match self {
178            PatOrWild::Wild => PatOrWild::Wild,
179            PatOrWild::Pat(pat) => PatOrWild::Pat(pat),
180        }
181    }
182}
183
184impl<'p, Cx: PatCx> Copy for PatOrWild<'p, Cx> {}
185
186impl<'p, Cx: PatCx> PatOrWild<'p, Cx> {
187    pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
188        match self {
189            PatOrWild::Wild => None,
190            PatOrWild::Pat(pat) => Some(pat),
191        }
192    }
193    pub(crate) fn ctor(self) -> &'p Constructor<Cx> {
194        match self {
195            PatOrWild::Wild => &Wildcard,
196            PatOrWild::Pat(pat) => pat.ctor(),
197        }
198    }
199
200    pub(crate) fn is_or_pat(&self) -> bool {
201        match self {
202            PatOrWild::Wild => false,
203            PatOrWild::Pat(pat) => pat.is_or_pat(),
204        }
205    }
206
207    /// Expand this or-pattern into its alternatives. This only expands one or-pattern; use
208    /// `flatten_or_pat` to recursively expand nested or-patterns.
209    pub(crate) fn expand_or_pat(self) -> SmallVec<[Self; 1]> {
210        match self {
211            PatOrWild::Pat(pat) if pat.is_or_pat() => {
212                pat.iter_fields().map(|ipat| PatOrWild::Pat(&ipat.pat)).collect()
213            }
214            _ => smallvec![self],
215        }
216    }
217
218    /// Recursively expand this (possibly-nested) or-pattern into its alternatives.
219    pub(crate) fn flatten_or_pat(self) -> SmallVec<[Self; 1]> {
220        match self {
221            PatOrWild::Pat(pat) if pat.is_or_pat() => pat
222                .iter_fields()
223                .flat_map(|ipat| PatOrWild::Pat(&ipat.pat).flatten_or_pat())
224                .collect(),
225            _ => smallvec![self],
226        }
227    }
228
229    /// Specialize this pattern with a constructor.
230    /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
231    pub(crate) fn specialize(
232        &self,
233        other_ctor: &Constructor<Cx>,
234        ctor_arity: usize,
235    ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> {
236        match self {
237            PatOrWild::Wild => (0..ctor_arity).map(|_| PatOrWild::Wild).collect(),
238            PatOrWild::Pat(pat) => pat.specialize(other_ctor, ctor_arity),
239        }
240    }
241}
242
243impl<'p, Cx: PatCx> fmt::Debug for PatOrWild<'p, Cx> {
244    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245        match self {
246            PatOrWild::Wild => write!(f, "_"),
247            PatOrWild::Pat(pat) => pat.fmt(f),
248        }
249    }
250}
251
252/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
253/// purposes. As such they don't use interning and can be cloned.
254pub struct WitnessPat<Cx: PatCx> {
255    ctor: Constructor<Cx>,
256    pub(crate) fields: Vec<WitnessPat<Cx>>,
257    ty: Cx::Ty,
258}
259
260impl<Cx: PatCx> Clone for WitnessPat<Cx> {
261    fn clone(&self) -> Self {
262        Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
263    }
264}
265
266impl<Cx: PatCx> WitnessPat<Cx> {
267    pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
268        Self { ctor, fields, ty }
269    }
270    /// Create a wildcard pattern for this type. If the type is empty, we create a `!` pattern.
271    pub(crate) fn wildcard(cx: &Cx, ty: Cx::Ty) -> Self {
272        let is_empty = cx.ctors_for_ty(&ty).is_ok_and(|ctors| ctors.all_empty());
273        let ctor = if is_empty { Never } else { Wildcard };
274        Self::new(ctor, Vec::new(), ty)
275    }
276
277    /// Construct a pattern that matches everything that starts with this constructor.
278    /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
279    /// `Some(_)`.
280    pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self {
281        if matches!(ctor, Wildcard) {
282            return Self::wildcard(cx, ty);
283        }
284        let fields = cx
285            .ctor_sub_tys(&ctor, &ty)
286            .filter(|(_, PrivateUninhabitedField(skip))| !skip)
287            .map(|(ty, _)| Self::wildcard(cx, ty))
288            .collect();
289        Self::new(ctor, fields, ty)
290    }
291
292    pub fn ctor(&self) -> &Constructor<Cx> {
293        &self.ctor
294    }
295    pub fn ty(&self) -> &Cx::Ty {
296        &self.ty
297    }
298
299    pub fn is_never_pattern(&self) -> bool {
300        match self.ctor() {
301            Never => true,
302            Or => self.fields.iter().all(|p| p.is_never_pattern()),
303            _ => self.fields.iter().any(|p| p.is_never_pattern()),
304        }
305    }
306
307    pub fn iter_fields(&self) -> impl Iterator<Item = &WitnessPat<Cx>> {
308        self.fields.iter()
309    }
310}
311
312/// This is best effort and not good enough for a `Display` impl.
313impl<Cx: PatCx> fmt::Debug for WitnessPat<Cx> {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        self.ctor().fmt_fields(f, self.ty(), self.fields.iter())
316    }
317}