about summary refs log tree commit diff
path: root/compiler/rustc_pattern_analysis/src/pat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_pattern_analysis/src/pat.rs')
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs162
1 files changed, 77 insertions, 85 deletions
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 404651124ad..0cc8477b7cd 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -5,16 +5,11 @@ use std::fmt;
 
 use smallvec::{smallvec, SmallVec};
 
-use rustc_data_structures::captures::Captures;
-use rustc_middle::ty::{self, Ty};
-use rustc_span::{Span, DUMMY_SP};
+use crate::constructor::{Constructor, Slice, SliceKind};
+use crate::usefulness::PlaceCtxt;
+use crate::{Captures, TypeCx};
 
 use self::Constructor::*;
-use self::SliceKind::*;
-
-use crate::constructor::{Constructor, SliceKind};
-use crate::cx::MatchCheckCtxt;
-use crate::usefulness::PatCtxt;
 
 /// Values and patterns can be represented as a constructor applied to some fields. This represents
 /// a pattern in this form.
@@ -27,34 +22,34 @@ use crate::usefulness::PatCtxt;
 /// 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`.
-pub struct DeconstructedPat<'p, 'tcx> {
-    ctor: Constructor<'tcx>,
-    fields: &'p [DeconstructedPat<'p, 'tcx>],
-    ty: Ty<'tcx>,
-    span: Span,
+pub struct DeconstructedPat<'p, Cx: TypeCx> {
+    ctor: Constructor<Cx>,
+    fields: &'p [DeconstructedPat<'p, Cx>],
+    ty: Cx::Ty,
+    data: Cx::PatData,
     /// Whether removing this arm would change the behavior of the match expression.
     useful: Cell<bool>,
 }
 
-impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
-    pub fn wildcard(ty: Ty<'tcx>, span: Span) -> Self {
-        Self::new(Wildcard, &[], ty, span)
+impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
+    pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self {
+        Self::new(Wildcard, &[], ty, data)
     }
 
     pub fn new(
-        ctor: Constructor<'tcx>,
-        fields: &'p [DeconstructedPat<'p, 'tcx>],
-        ty: Ty<'tcx>,
-        span: Span,
+        ctor: Constructor<Cx>,
+        fields: &'p [DeconstructedPat<'p, Cx>],
+        ty: Cx::Ty,
+        data: Cx::PatData,
     ) -> Self {
-        DeconstructedPat { ctor, fields, ty, span, useful: Cell::new(false) }
+        DeconstructedPat { ctor, fields, ty, data, useful: Cell::new(false) }
     }
 
     pub(crate) fn is_or_pat(&self) -> bool {
         matches!(self.ctor, Or)
     }
     /// Expand this (possibly-nested) or-pattern into its alternatives.
-    pub(crate) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> {
+    pub(crate) fn flatten_or_pat(&self) -> SmallVec<[&Self; 1]> {
         if self.is_or_pat() {
             self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect()
         } else {
@@ -62,66 +57,64 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
         }
     }
 
-    pub fn ctor(&self) -> &Constructor<'tcx> {
+    pub fn ctor(&self) -> &Constructor<Cx> {
         &self.ctor
     }
-    pub fn ty(&self) -> Ty<'tcx> {
+    pub fn ty(&self) -> Cx::Ty {
         self.ty
     }
-    pub fn span(&self) -> Span {
-        self.span
+    pub fn data(&self) -> &Cx::PatData {
+        &self.data
     }
 
     pub fn iter_fields<'a>(
         &'a self,
-    ) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> {
+    ) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
         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,
-        pcx: &PatCtxt<'_, 'p, 'tcx>,
-        other_ctor: &Constructor<'tcx>,
-    ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
+        &self,
+        pcx: &PlaceCtxt<'a, 'p, Cx>,
+        other_ctor: &Constructor<Cx>,
+    ) -> SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]> {
+        let wildcard_sub_tys = || {
+            let tys = pcx.ctor_sub_tys(other_ctor);
+            tys.iter()
+                .map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default()))
+                .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
+                .collect()
+        };
         match (&self.ctor, other_ctor) {
-            (Wildcard, _) => {
-                // We return a wildcard for each field of `other_ctor`.
-                pcx.cx.ctor_wildcard_fields(other_ctor, pcx.ty).iter().collect()
-            }
-            (Slice(self_slice), Slice(other_slice))
-                if self_slice.arity() != other_slice.arity() =>
-            {
-                // The only tricky case: two slices of different arity. Since `self_slice` covers
-                // `other_slice`, `self_slice` must be `VarLen`, i.e. of the form
-                // `[prefix, .., suffix]`. Moreover `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.
-                match self_slice.kind {
-                    FixedLen(_) => bug!("{:?} doesn't cover {:?}", self_slice, other_slice),
-                    VarLen(prefix, suffix) => {
-                        let (ty::Slice(inner_ty) | ty::Array(inner_ty, _)) = *self.ty.kind() else {
-                            bug!("bad slice pattern {:?} {:?}", self.ctor, self.ty);
-                        };
-                        let prefix = &self.fields[..prefix];
-                        let suffix = &self.fields[self_slice.arity() - suffix..];
-                        let wildcard: &_ = pcx
-                            .cx
-                            .pattern_arena
-                            .alloc(DeconstructedPat::wildcard(inner_ty, DUMMY_SP));
-                        let extra_wildcards = other_slice.arity() - self_slice.arity();
-                        let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
-                        prefix.iter().chain(extra_wildcards).chain(suffix).collect()
-                    }
+            // 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.
+            (
+                &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] = &self.fields[i];
+                }
+                for i in 0..suffix {
+                    fields[new_arity - 1 - i] = &self.fields[self.fields.len() - 1 - i];
                 }
+                fields
             }
             _ => self.fields.iter().collect(),
         }
     }
 
-    /// We keep track for each pattern if it was ever useful during the analysis. This is used
-    /// with `redundant_spans` to report redundant subpatterns arising from or patterns.
+    /// 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.
     pub(crate) fn set_useful(&self) {
         self.useful.set(true)
     }
@@ -139,19 +132,19 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
         }
     }
 
-    /// Report the spans of subpatterns that were not useful, if any.
-    pub(crate) fn redundant_spans(&self) -> Vec<Span> {
-        let mut spans = Vec::new();
-        self.collect_redundant_spans(&mut spans);
-        spans
+    /// 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
     }
-    fn collect_redundant_spans(&self, spans: &mut Vec<Span>) {
+    fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
         // We don't look at subpatterns if we already reported the whole pattern as redundant.
         if !self.is_useful() {
-            spans.push(self.span);
+            subpats.push(self);
         } else {
             for p in self.iter_fields() {
-                p.collect_redundant_spans(spans);
+                p.collect_redundant_subpatterns(subpats);
             }
         }
     }
@@ -159,47 +152,46 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
 
 /// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
 /// `Display` impl.
-impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
+impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        MatchCheckCtxt::debug_pat(f, self)
+        Cx::debug_pat(f, self)
     }
 }
 
 /// 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, Clone)]
-pub struct WitnessPat<'tcx> {
-    ctor: Constructor<'tcx>,
-    pub(crate) fields: Vec<WitnessPat<'tcx>>,
-    ty: Ty<'tcx>,
+pub struct WitnessPat<Cx: TypeCx> {
+    ctor: Constructor<Cx>,
+    pub(crate) fields: Vec<WitnessPat<Cx>>,
+    ty: Cx::Ty,
 }
 
-impl<'tcx> WitnessPat<'tcx> {
-    pub(crate) fn new(ctor: Constructor<'tcx>, fields: Vec<Self>, ty: Ty<'tcx>) -> Self {
+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: Ty<'tcx>) -> Self {
+    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(pcx: &PatCtxt<'_, '_, 'tcx>, ctor: Constructor<'tcx>) -> Self {
-        let field_tys =
-            pcx.cx.ctor_wildcard_fields(&ctor, pcx.ty).iter().map(|deco_pat| deco_pat.ty());
-        let fields = field_tys.map(|ty| Self::wildcard(ty)).collect();
+    pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, '_, Cx>, ctor: Constructor<Cx>) -> Self {
+        let field_tys = pcx.ctor_sub_tys(&ctor);
+        let fields = field_tys.iter().map(|ty| Self::wildcard(*ty)).collect();
         Self::new(ctor, fields, pcx.ty)
     }
 
-    pub fn ctor(&self) -> &Constructor<'tcx> {
+    pub fn ctor(&self) -> &Constructor<Cx> {
         &self.ctor
     }
-    pub fn ty(&self) -> Ty<'tcx> {
+    pub fn ty(&self) -> Cx::Ty {
         self.ty
     }
 
-    pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a WitnessPat<'tcx>> {
+    pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a WitnessPat<Cx>> {
         self.fields.iter()
     }
 }