mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 04:57:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			321 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			321 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! 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};
 | |
| 
 | |
| use crate::constructor::{Constructor, Slice, SliceKind};
 | |
| use crate::{PrivateUninhabitedField, TypeCx};
 | |
| 
 | |
| use self::Constructor::*;
 | |
| 
 | |
| /// 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))
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Values and patterns can be represented as a constructor applied to some fields. This represents
 | |
| /// 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.
 | |
| pub struct DeconstructedPat<Cx: TypeCx> {
 | |
|     ctor: Constructor<Cx>,
 | |
|     fields: Vec<DeconstructedPat<Cx>>,
 | |
|     ty: Cx::Ty,
 | |
|     /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
 | |
|     /// correspond to a user-supplied pattern.
 | |
|     data: Option<Cx::PatData>,
 | |
|     /// Globally-unique id used to track usefulness at the level of subpatterns.
 | |
|     pub(crate) uid: PatId,
 | |
| }
 | |
| 
 | |
| impl<Cx: TypeCx> DeconstructedPat<Cx> {
 | |
|     pub fn wildcard(ty: Cx::Ty) -> Self {
 | |
|         DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None, uid: PatId::new() }
 | |
|     }
 | |
| 
 | |
|     pub fn new(
 | |
|         ctor: Constructor<Cx>,
 | |
|         fields: Vec<DeconstructedPat<Cx>>,
 | |
|         ty: Cx::Ty,
 | |
|         data: Cx::PatData,
 | |
|     ) -> Self {
 | |
|         DeconstructedPat { ctor, fields, ty, data: Some(data), uid: PatId::new() }
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn is_or_pat(&self) -> bool {
 | |
|         matches!(self.ctor, Or)
 | |
|     }
 | |
| 
 | |
|     pub fn ctor(&self) -> &Constructor<Cx> {
 | |
|         &self.ctor
 | |
|     }
 | |
|     pub fn ty(&self) -> &Cx::Ty {
 | |
|         &self.ty
 | |
|     }
 | |
|     /// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that
 | |
|     /// does not correspond to a user-supplied pattern.
 | |
|     pub fn data(&self) -> Option<&Cx::PatData> {
 | |
|         self.data.as_ref()
 | |
|     }
 | |
| 
 | |
|     pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a DeconstructedPat<Cx>> {
 | |
|         self.fields.iter()
 | |
|     }
 | |
| 
 | |
|     /// Specialize this pattern with a constructor.
 | |
|     /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
 | |
|     pub(crate) fn specialize<'a>(
 | |
|         &'a self,
 | |
|         other_ctor: &Constructor<Cx>,
 | |
|         ctor_arity: usize,
 | |
|     ) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
 | |
|         let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect();
 | |
|         match (&self.ctor, other_ctor) {
 | |
|             // Return a wildcard for each field of `other_ctor`.
 | |
|             (Wildcard, _) => wildcard_sub_tys(),
 | |
|             // Skip this column.
 | |
|             (_, PrivateUninhabited) => smallvec![],
 | |
|             // 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.
 | |
|             (
 | |
|                 &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.
 | |
|                 let mut fields: SmallVec<[_; 2]> = wildcard_sub_tys();
 | |
|                 // Fill in the fields from both ends.
 | |
|                 let new_arity = fields.len();
 | |
|                 for i in 0..prefix {
 | |
|                     fields[i] = PatOrWild::Pat(&self.fields[i]);
 | |
|                 }
 | |
|                 for i in 0..suffix {
 | |
|                     fields[new_arity - 1 - i] =
 | |
|                         PatOrWild::Pat(&self.fields[self.fields.len() - 1 - i]);
 | |
|                 }
 | |
|                 fields
 | |
|             }
 | |
|             _ => self.fields.iter().map(PatOrWild::Pat).collect(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// 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;
 | |
|         }
 | |
| 
 | |
|         for p in self.iter_fields() {
 | |
|             p.walk(it)
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// This is best effort and not good enough for a `Display` impl.
 | |
| impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
 | |
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | |
|         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(", ");
 | |
| 
 | |
|         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, "(")?;
 | |
|                 for p in pat.iter_fields() {
 | |
|                     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 => {
 | |
|                 let subpattern = pat.iter_fields().next().unwrap();
 | |
|                 write!(f, "&{:?}", subpattern)
 | |
|             }
 | |
|             Slice(slice) => {
 | |
|                 let mut subpatterns = pat.iter_fields();
 | |
|                 write!(f, "[")?;
 | |
|                 match slice.kind {
 | |
|                     SliceKind::FixedLen(_) => {
 | |
|                         for p in subpatterns {
 | |
|                             write!(f, "{}{:?}", start_or_comma(), p)?;
 | |
|                         }
 | |
|                     }
 | |
|                     SliceKind::VarLen(prefix_len, _) => {
 | |
|                         for p in subpatterns.by_ref().take(prefix_len) {
 | |
|                             write!(f, "{}{:?}", start_or_comma(), p)?;
 | |
|                         }
 | |
|                         write!(f, "{}", start_or_comma())?;
 | |
|                         write!(f, "..")?;
 | |
|                         for p in subpatterns {
 | |
|                             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 => {
 | |
|                 for pat in pat.iter_fields() {
 | |
|                     write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
 | |
|                 }
 | |
|                 Ok(())
 | |
|             }
 | |
|             Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
 | |
|                 write!(f, "_ : {:?}", pat.ty())
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// 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.
 | |
|     Pat(&'p DeconstructedPat<Cx>),
 | |
| }
 | |
| 
 | |
| 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> {}
 | |
| 
 | |
| impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
 | |
|     pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
 | |
|         match self {
 | |
|             PatOrWild::Wild => None,
 | |
|             PatOrWild::Pat(pat) => Some(pat),
 | |
|         }
 | |
|     }
 | |
|     pub(crate) fn ctor(self) -> &'p Constructor<Cx> {
 | |
|         match self {
 | |
|             PatOrWild::Wild => &Wildcard,
 | |
|             PatOrWild::Pat(pat) => pat.ctor(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn is_or_pat(&self) -> bool {
 | |
|         match self {
 | |
|             PatOrWild::Wild => false,
 | |
|             PatOrWild::Pat(pat) => pat.is_or_pat(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Expand this (possibly-nested) or-pattern into its alternatives.
 | |
|     pub(crate) fn flatten_or_pat(self) -> SmallVec<[Self; 1]> {
 | |
|         match self {
 | |
|             PatOrWild::Pat(pat) if pat.is_or_pat() => {
 | |
|                 pat.iter_fields().flat_map(|p| PatOrWild::Pat(p).flatten_or_pat()).collect()
 | |
|             }
 | |
|             _ => 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>,
 | |
|         ctor_arity: usize,
 | |
|     ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> {
 | |
|         match self {
 | |
|             PatOrWild::Wild => (0..ctor_arity).map(|_| PatOrWild::Wild).collect(),
 | |
|             PatOrWild::Pat(pat) => pat.specialize(other_ctor, ctor_arity),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> {
 | |
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | |
|         match self {
 | |
|             PatOrWild::Wild => write!(f, "_"),
 | |
|             PatOrWild::Pat(pat) => pat.fmt(f),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// 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.
 | |
| #[derive(Debug)]
 | |
| pub struct WitnessPat<Cx: TypeCx> {
 | |
|     ctor: Constructor<Cx>,
 | |
|     pub(crate) fields: Vec<WitnessPat<Cx>>,
 | |
|     ty: Cx::Ty,
 | |
| }
 | |
| 
 | |
| impl<Cx: TypeCx> Clone for WitnessPat<Cx> {
 | |
|     fn clone(&self) -> Self {
 | |
|         Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<Cx: TypeCx> WitnessPat<Cx> {
 | |
|     pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
 | |
|         Self { ctor, fields, ty }
 | |
|     }
 | |
|     pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
 | |
|         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(_)`.
 | |
|     pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self {
 | |
|         let fields = cx
 | |
|             .ctor_sub_tys(&ctor, &ty)
 | |
|             .filter(|(_, PrivateUninhabitedField(skip))| !skip)
 | |
|             .map(|(ty, _)| Self::wildcard(ty))
 | |
|             .collect();
 | |
|         Self::new(ctor, fields, ty)
 | |
|     }
 | |
| 
 | |
|     pub fn ctor(&self) -> &Constructor<Cx> {
 | |
|         &self.ctor
 | |
|     }
 | |
|     pub fn ty(&self) -> &Cx::Ty {
 | |
|         &self.ty
 | |
|     }
 | |
| 
 | |
|     pub fn iter_fields(&self) -> impl Iterator<Item = &WitnessPat<Cx>> {
 | |
|         self.fields.iter()
 | |
|     }
 | |
| }
 | 
