rustc_pattern_analysis/
rustc.rs

1use std::fmt;
2use std::iter::once;
3
4use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
5use rustc_arena::DroplessArena;
6use rustc_hir::HirId;
7use rustc_hir::def_id::DefId;
8use rustc_index::{Idx, IndexVec};
9use rustc_middle::middle::stability::EvalResult;
10use rustc_middle::mir::{self, Const};
11use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
12use rustc_middle::ty::layout::IntegerExt;
13use rustc_middle::ty::{
14    self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
15};
16use rustc_middle::{bug, span_bug};
17use rustc_session::lint;
18use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
19
20use crate::constructor::Constructor::*;
21use crate::constructor::{
22    IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
23};
24use crate::lints::lint_nonexhaustive_missing_variants;
25use crate::pat_column::PatternColumn;
26use crate::rustc::print::EnumInfo;
27use crate::usefulness::{PlaceValidity, compute_match_usefulness};
28use crate::{PatCx, PrivateUninhabitedField, errors};
29
30mod print;
31
32// Re-export rustc-specific versions of all these types.
33pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcPatCtxt<'p, 'tcx>>;
34pub type ConstructorSet<'p, 'tcx> = crate::constructor::ConstructorSet<RustcPatCtxt<'p, 'tcx>>;
35pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcPatCtxt<'p, 'tcx>>;
36pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcPatCtxt<'p, 'tcx>>;
37pub type RedundancyExplanation<'p, 'tcx> =
38    crate::usefulness::RedundancyExplanation<'p, RustcPatCtxt<'p, 'tcx>>;
39pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcPatCtxt<'p, 'tcx>>;
40pub type UsefulnessReport<'p, 'tcx> =
41    crate::usefulness::UsefulnessReport<'p, RustcPatCtxt<'p, 'tcx>>;
42pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcPatCtxt<'p, 'tcx>>;
43
44/// A type which has gone through `cx.reveal_opaque_ty`, i.e. if it was opaque it was replaced by
45/// the hidden type if allowed in the current body. This ensures we consistently inspect the hidden
46/// types when we should.
47///
48/// Use `.inner()` or deref to get to the `Ty<'tcx>`.
49#[repr(transparent)]
50#[derive(Clone, Copy, PartialEq, Eq, Hash)]
51pub struct RevealedTy<'tcx>(Ty<'tcx>);
52
53impl<'tcx> fmt::Display for RevealedTy<'tcx> {
54    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
55        self.0.fmt(fmt)
56    }
57}
58
59impl<'tcx> fmt::Debug for RevealedTy<'tcx> {
60    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
61        self.0.fmt(fmt)
62    }
63}
64
65impl<'tcx> std::ops::Deref for RevealedTy<'tcx> {
66    type Target = Ty<'tcx>;
67    fn deref(&self) -> &Self::Target {
68        &self.0
69    }
70}
71
72impl<'tcx> RevealedTy<'tcx> {
73    pub fn inner(self) -> Ty<'tcx> {
74        self.0
75    }
76}
77
78#[derive(Clone)]
79pub struct RustcPatCtxt<'p, 'tcx: 'p> {
80    pub tcx: TyCtxt<'tcx>,
81    pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
82    /// The module in which the match occurs. This is necessary for
83    /// checking inhabited-ness of types because whether a type is (visibly)
84    /// inhabited can depend on whether it was defined in the current module or
85    /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
86    /// outside its module and should not be matchable with an empty match statement.
87    pub module: DefId,
88    pub typing_env: ty::TypingEnv<'tcx>,
89    /// To allocate the result of `self.ctor_sub_tys()`
90    pub dropless_arena: &'p DroplessArena,
91    /// Lint level at the match.
92    pub match_lint_level: HirId,
93    /// The span of the whole match, if applicable.
94    pub whole_match_span: Option<Span>,
95    /// Span of the scrutinee.
96    pub scrut_span: Span,
97    /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns.
98    pub refutable: bool,
99    /// Whether the data at the scrutinee is known to be valid. This is false if the scrutinee comes
100    /// from a union field, a pointer deref, or a reference deref (pending opsem decisions).
101    pub known_valid_scrutinee: bool,
102}
103
104impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        f.debug_struct("RustcPatCtxt").finish()
107    }
108}
109
110impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
111    /// Type inference occasionally gives us opaque types in places where corresponding patterns
112    /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
113    /// types, we use the corresponding concrete type if possible.
114    // FIXME(#132279): This will be unnecessary once we have a TypingMode which supports revealing
115    // opaque types defined in a body.
116    #[inline]
117    pub fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
118        fn reveal_inner<'tcx>(cx: &RustcPatCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
119            let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!() };
120            if let Some(local_def_id) = alias_ty.def_id.as_local() {
121                let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
122                if let Some(ty) = cx.reveal_opaque_key(key) {
123                    return RevealedTy(ty);
124                }
125            }
126            RevealedTy(ty)
127        }
128        if let ty::Alias(ty::Opaque, _) = ty.kind() {
129            reveal_inner(self, ty)
130        } else {
131            RevealedTy(ty)
132        }
133    }
134
135    /// Returns the hidden type corresponding to this key if the body under analysis is allowed to
136    /// know it.
137    fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
138        self.typeck_results
139            .concrete_opaque_types
140            .get(&key.def_id)
141            .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
142    }
143    // This can take a non-revealed `Ty` because it reveals opaques itself.
144    pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
145        !ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
146            self.tcx,
147            self.typing_env,
148            self.module,
149            &|key| self.reveal_opaque_key(key),
150        )
151    }
152
153    /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
154    pub fn is_foreign_non_exhaustive_enum(&self, ty: RevealedTy<'tcx>) -> bool {
155        match ty.kind() {
156            ty::Adt(def, ..) => def.variant_list_has_applicable_non_exhaustive(),
157            _ => false,
158        }
159    }
160
161    /// Whether the range denotes the fictitious values before `isize::MIN` or after
162    /// `usize::MAX`/`isize::MAX` (see doc of [`IntRange::split`] for why these exist).
163    pub fn is_range_beyond_boundaries(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> bool {
164        ty.is_ptr_sized_integral() && {
165            // The two invalid ranges are `NegInfinity..isize::MIN` (represented as
166            // `NegInfinity..0`), and `{u,i}size::MAX+1..PosInfinity`. `hoist_pat_range_bdy`
167            // converts `MAX+1` to `PosInfinity`, and we couldn't have `PosInfinity` in `range.lo`
168            // otherwise.
169            let lo = self.hoist_pat_range_bdy(range.lo, ty);
170            matches!(lo, PatRangeBoundary::PosInfinity)
171                || matches!(range.hi, MaybeInfiniteInt::Finite(0))
172        }
173    }
174
175    pub(crate) fn variant_sub_tys(
176        &self,
177        ty: RevealedTy<'tcx>,
178        variant: &'tcx VariantDef,
179    ) -> impl Iterator<Item = (&'tcx FieldDef, RevealedTy<'tcx>)> {
180        let ty::Adt(_, args) = ty.kind() else { bug!() };
181        variant.fields.iter().map(move |field| {
182            let ty = field.ty(self.tcx, args);
183            // `field.ty()` doesn't normalize after instantiating.
184            let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
185            let ty = self.reveal_opaque_ty(ty);
186            (field, ty)
187        })
188    }
189
190    pub(crate) fn variant_index_for_adt(
191        ctor: &Constructor<'p, 'tcx>,
192        adt: ty::AdtDef<'tcx>,
193    ) -> VariantIdx {
194        match *ctor {
195            Variant(idx) => idx,
196            Struct | UnionField => {
197                assert!(!adt.is_enum());
198                FIRST_VARIANT
199            }
200            _ => bug!("bad constructor {:?} for adt {:?}", ctor, adt),
201        }
202    }
203
204    /// Returns the types of the fields for a given constructor. The result must have a length of
205    /// `ctor.arity()`.
206    pub(crate) fn ctor_sub_tys(
207        &self,
208        ctor: &Constructor<'p, 'tcx>,
209        ty: RevealedTy<'tcx>,
210    ) -> impl Iterator<Item = (RevealedTy<'tcx>, PrivateUninhabitedField)> + ExactSizeIterator {
211        fn reveal_and_alloc<'a, 'tcx>(
212            cx: &'a RustcPatCtxt<'_, 'tcx>,
213            iter: impl Iterator<Item = Ty<'tcx>>,
214        ) -> &'a [(RevealedTy<'tcx>, PrivateUninhabitedField)] {
215            cx.dropless_arena.alloc_from_iter(
216                iter.map(|ty| cx.reveal_opaque_ty(ty))
217                    .map(|ty| (ty, PrivateUninhabitedField(false))),
218            )
219        }
220        let cx = self;
221        let slice = match ctor {
222            Struct | Variant(_) | UnionField => match ty.kind() {
223                ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
224                ty::Adt(adt, _) => {
225                    let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
226                    let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
227                        let is_visible =
228                            adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
229                        let is_uninhabited = cx.is_uninhabited(*ty);
230                        let is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| {
231                            stab.is_unstable() && stab.feature != sym::rustc_private
232                        });
233                        let skip = is_uninhabited && (!is_visible || is_unstable);
234                        (ty, PrivateUninhabitedField(skip))
235                    });
236                    cx.dropless_arena.alloc_from_iter(tys)
237                }
238                _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
239            },
240            Ref => match ty.kind() {
241                ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)),
242                _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"),
243            },
244            Slice(slice) => match ty.builtin_index() {
245                Some(ty) => {
246                    let arity = slice.arity();
247                    reveal_and_alloc(cx, (0..arity).map(|_| ty))
248                }
249                None => bug!("bad slice pattern {:?} {:?}", ctor, ty),
250            },
251            DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())),
252            Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
253            | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
254            | PrivateUninhabited | Wildcard => &[],
255            Or => {
256                bug!("called `Fields::wildcards` on an `Or` ctor")
257            }
258        };
259        slice.iter().copied()
260    }
261
262    /// The number of fields for this constructor.
263    pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: RevealedTy<'tcx>) -> usize {
264        match ctor {
265            Struct | Variant(_) | UnionField => match ty.kind() {
266                ty::Tuple(fs) => fs.len(),
267                ty::Adt(adt, ..) => {
268                    let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
269                    adt.variant(variant_idx).fields.len()
270                }
271                _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
272            },
273            Ref | DerefPattern(_) => 1,
274            Slice(slice) => slice.arity(),
275            Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
276            | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
277            | PrivateUninhabited | Wildcard => 0,
278            Or => bug!("The `Or` constructor doesn't have a fixed arity"),
279        }
280    }
281
282    /// Creates a set that represents all the constructors of `ty`.
283    ///
284    /// See [`crate::constructor`] for considerations of emptiness.
285    pub fn ctors_for_ty(
286        &self,
287        ty: RevealedTy<'tcx>,
288    ) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
289        let cx = self;
290        let make_uint_range = |start, end| {
291            IntRange::from_range(
292                MaybeInfiniteInt::new_finite_uint(start),
293                MaybeInfiniteInt::new_finite_uint(end),
294                RangeEnd::Included,
295            )
296        };
297        // Abort on type error.
298        ty.error_reported()?;
299        // This determines the set of all possible constructors for the type `ty`. For numbers,
300        // arrays and slices we use ranges and variable-length slices when appropriate.
301        Ok(match ty.kind() {
302            ty::Bool => ConstructorSet::Bool,
303            ty::Char => {
304                // The valid Unicode Scalar Value ranges.
305                ConstructorSet::Integers {
306                    range_1: make_uint_range('\u{0000}' as u128, '\u{D7FF}' as u128),
307                    range_2: Some(make_uint_range('\u{E000}' as u128, '\u{10FFFF}' as u128)),
308                }
309            }
310            &ty::Int(ity) => {
311                let range = if ty.is_ptr_sized_integral() {
312                    // The min/max values of `isize` are not allowed to be observed.
313                    IntRange {
314                        lo: MaybeInfiniteInt::NegInfinity,
315                        hi: MaybeInfiniteInt::PosInfinity,
316                    }
317                } else {
318                    let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
319                    let min = 1u128 << (size - 1);
320                    let max = min - 1;
321                    let min = MaybeInfiniteInt::new_finite_int(min, size);
322                    let max = MaybeInfiniteInt::new_finite_int(max, size);
323                    IntRange::from_range(min, max, RangeEnd::Included)
324                };
325                ConstructorSet::Integers { range_1: range, range_2: None }
326            }
327            &ty::Uint(uty) => {
328                let range = if ty.is_ptr_sized_integral() {
329                    // The max value of `usize` is not allowed to be observed.
330                    let lo = MaybeInfiniteInt::new_finite_uint(0);
331                    IntRange { lo, hi: MaybeInfiniteInt::PosInfinity }
332                } else {
333                    let size = Integer::from_uint_ty(&cx.tcx, uty).size();
334                    let max = size.truncate(u128::MAX);
335                    make_uint_range(0, max)
336                };
337                ConstructorSet::Integers { range_1: range, range_2: None }
338            }
339            ty::Slice(sub_ty) => ConstructorSet::Slice {
340                array_len: None,
341                subtype_is_empty: cx.is_uninhabited(*sub_ty),
342            },
343            ty::Array(sub_ty, len) => {
344                // We treat arrays of a constant but unknown length like slices.
345                ConstructorSet::Slice {
346                    array_len: len.try_to_target_usize(cx.tcx).map(|l| l as usize),
347                    subtype_is_empty: cx.is_uninhabited(*sub_ty),
348                }
349            }
350            ty::Adt(def, args) if def.is_enum() => {
351                let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty);
352                if def.variants().is_empty() && !is_declared_nonexhaustive {
353                    ConstructorSet::NoConstructors
354                } else {
355                    let mut variants =
356                        IndexVec::from_elem(VariantVisibility::Visible, def.variants());
357                    for (idx, v) in def.variants().iter_enumerated() {
358                        let variant_def_id = def.variant(idx).def_id;
359                        // Visibly uninhabited variants.
360                        let is_inhabited = v
361                            .inhabited_predicate(cx.tcx, *def)
362                            .instantiate(cx.tcx, args)
363                            .apply_revealing_opaque(cx.tcx, cx.typing_env, cx.module, &|key| {
364                                cx.reveal_opaque_key(key)
365                            });
366                        // Variants that depend on a disabled unstable feature.
367                        let is_unstable = matches!(
368                            cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None),
369                            EvalResult::Deny { .. }
370                        );
371                        // Foreign `#[doc(hidden)]` variants.
372                        let is_doc_hidden =
373                            cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
374                        let visibility = if !is_inhabited {
375                            // FIXME: handle empty+hidden
376                            VariantVisibility::Empty
377                        } else if is_unstable || is_doc_hidden {
378                            VariantVisibility::Hidden
379                        } else {
380                            VariantVisibility::Visible
381                        };
382                        variants[idx] = visibility;
383                    }
384
385                    ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
386                }
387            }
388            ty::Adt(def, _) if def.is_union() => ConstructorSet::Union,
389            ty::Adt(..) | ty::Tuple(..) => {
390                ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) }
391            }
392            ty::Ref(..) => ConstructorSet::Ref,
393            ty::Never => ConstructorSet::NoConstructors,
394            // This type is one for which we cannot list constructors, like `str` or `f64`.
395            // FIXME(Nadrieril): which of these are actually allowed?
396            ty::Float(_)
397            | ty::Str
398            | ty::Foreign(_)
399            | ty::RawPtr(_, _)
400            | ty::FnDef(_, _)
401            | ty::FnPtr(..)
402            | ty::Pat(_, _)
403            | ty::Dynamic(_, _, _)
404            | ty::Closure(..)
405            | ty::CoroutineClosure(..)
406            | ty::Coroutine(_, _)
407            | ty::UnsafeBinder(_)
408            | ty::Alias(_, _)
409            | ty::Param(_)
410            | ty::Error(_) => ConstructorSet::Unlistable,
411            ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
412                bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
413            }
414        })
415    }
416
417    pub(crate) fn lower_pat_range_bdy(
418        &self,
419        bdy: PatRangeBoundary<'tcx>,
420        ty: RevealedTy<'tcx>,
421    ) -> MaybeInfiniteInt {
422        match bdy {
423            PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity,
424            PatRangeBoundary::Finite(value) => {
425                let bits = value.eval_bits(self.tcx, self.typing_env);
426                match *ty.kind() {
427                    ty::Int(ity) => {
428                        let size = Integer::from_int_ty(&self.tcx, ity).size().bits();
429                        MaybeInfiniteInt::new_finite_int(bits, size)
430                    }
431                    _ => MaybeInfiniteInt::new_finite_uint(bits),
432                }
433            }
434            PatRangeBoundary::PosInfinity => MaybeInfiniteInt::PosInfinity,
435        }
436    }
437
438    /// Note: the input patterns must have been lowered through
439    /// `rustc_mir_build::thir::pattern::check_match::MatchVisitor::lower_pattern`.
440    pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
441        let cx = self;
442        let ty = cx.reveal_opaque_ty(pat.ty);
443        let ctor;
444        let arity;
445        let fields: Vec<_>;
446        match &pat.kind {
447            PatKind::AscribeUserType { subpattern, .. }
448            | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
449            PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
450            PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
451                ctor = Wildcard;
452                fields = vec![];
453                arity = 0;
454            }
455            PatKind::Deref { subpattern } => {
456                fields = vec![self.lower_pat(subpattern).at_index(0)];
457                arity = 1;
458                ctor = match ty.kind() {
459                    ty::Ref(..) => Ref,
460                    _ => span_bug!(
461                        pat.span,
462                        "pattern has unexpected type: pat: {:?}, ty: {:?}",
463                        pat.kind,
464                        ty.inner()
465                    ),
466                };
467            }
468            PatKind::DerefPattern { subpattern, .. } => {
469                // NB(deref_patterns): This assumes the deref pattern is matching on a trusted
470                // `DerefPure` type. If the `Deref` impl isn't trusted, exhaustiveness must take
471                // into account that multiple calls to deref may return different results. Hence
472                // multiple deref! patterns cannot be exhaustive together unless each is exhaustive
473                // by itself.
474                fields = vec![self.lower_pat(subpattern).at_index(0)];
475                arity = 1;
476                ctor = DerefPattern(cx.reveal_opaque_ty(subpattern.ty));
477            }
478            PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
479                match ty.kind() {
480                    ty::Tuple(fs) => {
481                        ctor = Struct;
482                        arity = fs.len();
483                        fields = subpatterns
484                            .iter()
485                            .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
486                            .collect();
487                    }
488                    ty::Adt(adt, _) => {
489                        ctor = match pat.kind {
490                            PatKind::Leaf { .. } if adt.is_union() => UnionField,
491                            PatKind::Leaf { .. } => Struct,
492                            PatKind::Variant { variant_index, .. } => Variant(variant_index),
493                            _ => bug!(),
494                        };
495                        let variant =
496                            &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
497                        arity = variant.fields.len();
498                        fields = subpatterns
499                            .iter()
500                            .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
501                            .collect();
502                    }
503                    _ => span_bug!(
504                        pat.span,
505                        "pattern has unexpected type: pat: {:?}, ty: {}",
506                        pat.kind,
507                        ty.inner()
508                    ),
509                }
510            }
511            PatKind::Constant { value } => {
512                match ty.kind() {
513                    ty::Bool => {
514                        ctor = match value.try_eval_bool(cx.tcx, cx.typing_env) {
515                            Some(b) => Bool(b),
516                            None => Opaque(OpaqueId::new()),
517                        };
518                        fields = vec![];
519                        arity = 0;
520                    }
521                    ty::Char | ty::Int(_) | ty::Uint(_) => {
522                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
523                            Some(bits) => {
524                                let x = match *ty.kind() {
525                                    ty::Int(ity) => {
526                                        let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
527                                        MaybeInfiniteInt::new_finite_int(bits, size)
528                                    }
529                                    _ => MaybeInfiniteInt::new_finite_uint(bits),
530                                };
531                                IntRange(IntRange::from_singleton(x))
532                            }
533                            None => Opaque(OpaqueId::new()),
534                        };
535                        fields = vec![];
536                        arity = 0;
537                    }
538                    ty::Float(ty::FloatTy::F16) => {
539                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
540                            Some(bits) => {
541                                use rustc_apfloat::Float;
542                                let value = rustc_apfloat::ieee::Half::from_bits(bits);
543                                F16Range(value, value, RangeEnd::Included)
544                            }
545                            None => Opaque(OpaqueId::new()),
546                        };
547                        fields = vec![];
548                        arity = 0;
549                    }
550                    ty::Float(ty::FloatTy::F32) => {
551                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
552                            Some(bits) => {
553                                use rustc_apfloat::Float;
554                                let value = rustc_apfloat::ieee::Single::from_bits(bits);
555                                F32Range(value, value, RangeEnd::Included)
556                            }
557                            None => Opaque(OpaqueId::new()),
558                        };
559                        fields = vec![];
560                        arity = 0;
561                    }
562                    ty::Float(ty::FloatTy::F64) => {
563                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
564                            Some(bits) => {
565                                use rustc_apfloat::Float;
566                                let value = rustc_apfloat::ieee::Double::from_bits(bits);
567                                F64Range(value, value, RangeEnd::Included)
568                            }
569                            None => Opaque(OpaqueId::new()),
570                        };
571                        fields = vec![];
572                        arity = 0;
573                    }
574                    ty::Float(ty::FloatTy::F128) => {
575                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
576                            Some(bits) => {
577                                use rustc_apfloat::Float;
578                                let value = rustc_apfloat::ieee::Quad::from_bits(bits);
579                                F128Range(value, value, RangeEnd::Included)
580                            }
581                            None => Opaque(OpaqueId::new()),
582                        };
583                        fields = vec![];
584                        arity = 0;
585                    }
586                    ty::Ref(_, t, _) if t.is_str() => {
587                        // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
588                        // with other `Deref` patterns. This could have been done in `const_to_pat`,
589                        // but that causes issues with the rest of the matching code.
590                        // So here, the constructor for a `"foo"` pattern is `&` (represented by
591                        // `Ref`), and has one field. That field has constructor `Str(value)` and no
592                        // subfields.
593                        // Note: `t` is `str`, not `&str`.
594                        let ty = self.reveal_opaque_ty(*t);
595                        let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat);
596                        ctor = Ref;
597                        fields = vec![subpattern.at_index(0)];
598                        arity = 1;
599                    }
600                    // All constants that can be structurally matched have already been expanded
601                    // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
602                    // opaque.
603                    _ => {
604                        ctor = Opaque(OpaqueId::new());
605                        fields = vec![];
606                        arity = 0;
607                    }
608                }
609            }
610            PatKind::Range(patrange) => {
611                let PatRange { lo, hi, end, .. } = patrange.as_ref();
612                let end = match end {
613                    rustc_hir::RangeEnd::Included => RangeEnd::Included,
614                    rustc_hir::RangeEnd::Excluded => RangeEnd::Excluded,
615                };
616                ctor = match ty.kind() {
617                    ty::Char | ty::Int(_) | ty::Uint(_) => {
618                        let lo = cx.lower_pat_range_bdy(*lo, ty);
619                        let hi = cx.lower_pat_range_bdy(*hi, ty);
620                        IntRange(IntRange::from_range(lo, hi, end))
621                    }
622                    ty::Float(fty) => {
623                        use rustc_apfloat::Float;
624                        let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env));
625                        let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env));
626                        match fty {
627                            ty::FloatTy::F16 => {
628                                use rustc_apfloat::ieee::Half;
629                                let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY);
630                                let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY);
631                                F16Range(lo, hi, end)
632                            }
633                            ty::FloatTy::F32 => {
634                                use rustc_apfloat::ieee::Single;
635                                let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY);
636                                let hi = hi.map(Single::from_bits).unwrap_or(Single::INFINITY);
637                                F32Range(lo, hi, end)
638                            }
639                            ty::FloatTy::F64 => {
640                                use rustc_apfloat::ieee::Double;
641                                let lo = lo.map(Double::from_bits).unwrap_or(-Double::INFINITY);
642                                let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY);
643                                F64Range(lo, hi, end)
644                            }
645                            ty::FloatTy::F128 => {
646                                use rustc_apfloat::ieee::Quad;
647                                let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY);
648                                let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY);
649                                F128Range(lo, hi, end)
650                            }
651                        }
652                    }
653                    _ => span_bug!(pat.span, "invalid type for range pattern: {}", ty.inner()),
654                };
655                fields = vec![];
656                arity = 0;
657            }
658            PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
659                let array_len = match ty.kind() {
660                    ty::Array(_, length) => Some(
661                        length
662                            .try_to_target_usize(cx.tcx)
663                            .expect("expected len of array pat to be definite")
664                            as usize,
665                    ),
666                    ty::Slice(_) => None,
667                    _ => span_bug!(pat.span, "bad ty {} for slice pattern", ty.inner()),
668                };
669                let kind = if slice.is_some() {
670                    SliceKind::VarLen(prefix.len(), suffix.len())
671                } else {
672                    SliceKind::FixedLen(prefix.len() + suffix.len())
673                };
674                ctor = Slice(Slice::new(array_len, kind));
675                fields = prefix
676                    .iter()
677                    .chain(suffix.iter())
678                    .map(|p| self.lower_pat(&*p))
679                    .enumerate()
680                    .map(|(i, p)| p.at_index(i))
681                    .collect();
682                arity = kind.arity();
683            }
684            PatKind::Or { .. } => {
685                ctor = Or;
686                let pats = expand_or_pat(pat);
687                fields = pats
688                    .into_iter()
689                    .map(|p| self.lower_pat(p))
690                    .enumerate()
691                    .map(|(i, p)| p.at_index(i))
692                    .collect();
693                arity = fields.len();
694            }
695            PatKind::Never => {
696                // A never pattern matches all the values of its type (namely none). Moreover it
697                // must be compatible with other constructors, since we can use `!` on a type like
698                // `Result<!, !>` which has other constructors. Hence we lower it as a wildcard.
699                ctor = Wildcard;
700                fields = vec![];
701                arity = 0;
702            }
703            PatKind::Error(_) => {
704                ctor = Opaque(OpaqueId::new());
705                fields = vec![];
706                arity = 0;
707            }
708        }
709        DeconstructedPat::new(ctor, fields, arity, ty, pat)
710    }
711
712    /// Convert back to a `thir::PatRangeBoundary` for diagnostic purposes.
713    /// Note: it is possible to get `isize/usize::MAX+1` here, as explained in the doc for
714    /// [`IntRange::split`]. This cannot be represented as a `Const`, so we represent it with
715    /// `PosInfinity`.
716    fn hoist_pat_range_bdy(
717        &self,
718        miint: MaybeInfiniteInt,
719        ty: RevealedTy<'tcx>,
720    ) -> PatRangeBoundary<'tcx> {
721        use MaybeInfiniteInt::*;
722        let tcx = self.tcx;
723        match miint {
724            NegInfinity => PatRangeBoundary::NegInfinity,
725            Finite(_) => {
726                let size = ty.primitive_size(tcx);
727                let bits = match *ty.kind() {
728                    ty::Int(_) => miint.as_finite_int(size.bits()).unwrap(),
729                    _ => miint.as_finite_uint().unwrap(),
730                };
731                match ScalarInt::try_from_uint(bits, size) {
732                    Some(scalar) => {
733                        let value = mir::Const::from_scalar(tcx, scalar.into(), ty.inner());
734                        PatRangeBoundary::Finite(value)
735                    }
736                    // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value
737                    // for a type, the problem isn't that the value is too small. So it must be too
738                    // large.
739                    None => PatRangeBoundary::PosInfinity,
740                }
741            }
742            PosInfinity => PatRangeBoundary::PosInfinity,
743        }
744    }
745
746    /// Prints an [`IntRange`] to a string for diagnostic purposes.
747    fn print_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> String {
748        use MaybeInfiniteInt::*;
749        let cx = self;
750        if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
751            "_".to_string()
752        } else if range.is_singleton() {
753            let lo = cx.hoist_pat_range_bdy(range.lo, ty);
754            let value = lo.as_finite().unwrap();
755            value.to_string()
756        } else {
757            // We convert to an inclusive range for diagnostics.
758            let mut end = rustc_hir::RangeEnd::Included;
759            let mut lo = cx.hoist_pat_range_bdy(range.lo, ty);
760            if matches!(lo, PatRangeBoundary::PosInfinity) {
761                // The only reason to get `PosInfinity` here is the special case where
762                // `hoist_pat_range_bdy` found `{u,i}size::MAX+1`. So the range denotes the
763                // fictitious values after `{u,i}size::MAX` (see [`IntRange::split`] for why we do
764                // this). We show this to the user as `usize::MAX..` which is slightly incorrect but
765                // probably clear enough.
766                lo = PatRangeBoundary::Finite(ty.numeric_max_val(cx.tcx).unwrap());
767            }
768            let hi = if let Some(hi) = range.hi.minus_one() {
769                hi
770            } else {
771                // The range encodes `..ty::MIN`, so we can't convert it to an inclusive range.
772                end = rustc_hir::RangeEnd::Excluded;
773                range.hi
774            };
775            let hi = cx.hoist_pat_range_bdy(hi, ty);
776            PatRange { lo, hi, end, ty: ty.inner() }.to_string()
777        }
778    }
779
780    /// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
781    ///
782    /// This panics for patterns that don't appear in diagnostics, like float ranges.
783    pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
784        let cx = self;
785        let print = |p| cx.print_witness_pat(p);
786        match pat.ctor() {
787            Bool(b) => b.to_string(),
788            Str(s) => s.to_string(),
789            IntRange(range) => return self.print_pat_range(range, *pat.ty()),
790            Struct | Variant(_) | UnionField => {
791                let enum_info = match *pat.ty().kind() {
792                    ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
793                        adt_def,
794                        variant_index: RustcPatCtxt::variant_index_for_adt(pat.ctor(), adt_def),
795                    },
796                    ty::Adt(..) | ty::Tuple(..) => EnumInfo::NotEnum,
797                    _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()),
798                };
799
800                let subpatterns = pat
801                    .iter_fields()
802                    .enumerate()
803                    .map(|(i, pat)| print::FieldPat {
804                        field: FieldIdx::new(i),
805                        pattern: print(pat),
806                        is_wildcard: would_print_as_wildcard(cx.tcx, pat),
807                    })
808                    .collect::<Vec<_>>();
809
810                let mut s = String::new();
811                print::write_struct_like(
812                    &mut s,
813                    self.tcx,
814                    pat.ty().inner(),
815                    &enum_info,
816                    &subpatterns,
817                )
818                .unwrap();
819                s
820            }
821            Ref => {
822                let mut s = String::new();
823                print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
824                s
825            }
826            DerefPattern(_) if pat.ty().is_box() && !self.tcx.features().deref_patterns() => {
827                // FIXME(deref_patterns): Remove this special handling once `box_patterns` is gone.
828                // HACK(@dianne): `box _` syntax is exposed on stable in diagnostics, e.g. to
829                // witness non-exhaustiveness of `match Box::new(0) { Box { .. } if false => {} }`.
830                // To avoid changing diagnostics before deref pattern syntax is finalized, let's use
831                // `box _` syntax unless `deref_patterns` is enabled.
832                format!("box {}", print(&pat.fields[0]))
833            }
834            DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])),
835            Slice(slice) => {
836                let (prefix_len, has_dot_dot) = match slice.kind {
837                    SliceKind::FixedLen(len) => (len, false),
838                    SliceKind::VarLen(prefix_len, _) => (prefix_len, true),
839                };
840
841                let (mut prefix, mut suffix) = pat.fields.split_at(prefix_len);
842
843                // If the pattern contains a `..`, but is applied to values of statically-known
844                // length (arrays), then we can slightly simplify diagnostics by merging any
845                // adjacent wildcard patterns into the `..`: `[x, _, .., _, y]` => `[x, .., y]`.
846                // (This simplification isn't allowed for slice values, because in that case
847                // `[x, .., y]` would match some slices that `[x, _, .., _, y]` would not.)
848                if has_dot_dot && slice.array_len.is_some() {
849                    while let [rest @ .., last] = prefix
850                        && would_print_as_wildcard(cx.tcx, last)
851                    {
852                        prefix = rest;
853                    }
854                    while let [first, rest @ ..] = suffix
855                        && would_print_as_wildcard(cx.tcx, first)
856                    {
857                        suffix = rest;
858                    }
859                }
860
861                let prefix = prefix.iter().map(print).collect::<Vec<_>>();
862                let suffix = suffix.iter().map(print).collect::<Vec<_>>();
863
864                let mut s = String::new();
865                print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
866                s
867            }
868            Never if self.tcx.features().never_patterns() => "!".to_string(),
869            Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
870            Missing { .. } => bug!(
871                "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
872                `Missing` should have been processed in `apply_constructors`"
873            ),
874            F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
875                bug!("can't convert to pattern: {:?}", pat)
876            }
877        }
878    }
879}
880
881/// Returns `true` if the given pattern would be printed as a wildcard (`_`).
882fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool {
883    match p.ctor() {
884        Constructor::IntRange(IntRange {
885            lo: MaybeInfiniteInt::NegInfinity,
886            hi: MaybeInfiniteInt::PosInfinity,
887        })
888        | Constructor::Wildcard
889        | Constructor::NonExhaustive
890        | Constructor::Hidden
891        | Constructor::PrivateUninhabited => true,
892        Constructor::Never if !tcx.features().never_patterns() => true,
893        _ => false,
894    }
895}
896
897impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
898    type Ty = RevealedTy<'tcx>;
899    type Error = ErrorGuaranteed;
900    type VariantIdx = VariantIdx;
901    type StrLit = Const<'tcx>;
902    type ArmData = HirId;
903    type PatData = &'p Pat<'tcx>;
904
905    fn is_exhaustive_patterns_feature_on(&self) -> bool {
906        self.tcx.features().exhaustive_patterns()
907    }
908
909    fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
910        self.ctor_arity(ctor, *ty)
911    }
912    fn ctor_sub_tys(
913        &self,
914        ctor: &crate::constructor::Constructor<Self>,
915        ty: &Self::Ty,
916    ) -> impl Iterator<Item = (Self::Ty, PrivateUninhabitedField)> + ExactSizeIterator {
917        self.ctor_sub_tys(ctor, *ty)
918    }
919    fn ctors_for_ty(
920        &self,
921        ty: &Self::Ty,
922    ) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> {
923        self.ctors_for_ty(*ty)
924    }
925
926    fn write_variant_name(
927        f: &mut fmt::Formatter<'_>,
928        ctor: &crate::constructor::Constructor<Self>,
929        ty: &Self::Ty,
930    ) -> fmt::Result {
931        if let ty::Adt(adt, _) = ty.kind() {
932            let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
933            write!(f, "{}", variant.name)?;
934        }
935        Ok(())
936    }
937
938    fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error {
939        span_bug!(self.scrut_span, "{}", fmt)
940    }
941
942    fn lint_overlapping_range_endpoints(
943        &self,
944        pat: &crate::pat::DeconstructedPat<Self>,
945        overlaps_on: IntRange,
946        overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
947    ) {
948        let overlap_as_pat = self.print_pat_range(&overlaps_on, *pat.ty());
949        let overlaps: Vec<_> = overlaps_with
950            .iter()
951            .map(|pat| pat.data().span)
952            .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span })
953            .collect();
954        let pat_span = pat.data().span;
955        self.tcx.emit_node_span_lint(
956            lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
957            self.match_lint_level,
958            pat_span,
959            errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
960        );
961    }
962
963    fn complexity_exceeded(&self) -> Result<(), Self::Error> {
964        let span = self.whole_match_span.unwrap_or(self.scrut_span);
965        Err(self.tcx.dcx().span_err(span, "reached pattern complexity limit"))
966    }
967
968    fn lint_non_contiguous_range_endpoints(
969        &self,
970        pat: &crate::pat::DeconstructedPat<Self>,
971        gap: IntRange,
972        gapped_with: &[&crate::pat::DeconstructedPat<Self>],
973    ) {
974        let &thir_pat = pat.data();
975        let thir::PatKind::Range(range) = &thir_pat.kind else { return };
976        // Only lint when the left range is an exclusive range.
977        if range.end != rustc_hir::RangeEnd::Excluded {
978            return;
979        }
980        // `pat` is an exclusive range like `lo..gap`. `gapped_with` contains ranges that start with
981        // `gap+1`.
982        let suggested_range: String = {
983            // Suggest `lo..=gap` instead.
984            let mut suggested_range = PatRange::clone(range);
985            suggested_range.end = rustc_hir::RangeEnd::Included;
986            suggested_range.to_string()
987        };
988        let gap_as_pat = self.print_pat_range(&gap, *pat.ty());
989        if gapped_with.is_empty() {
990            // If `gapped_with` is empty, `gap == T::MAX`.
991            self.tcx.emit_node_span_lint(
992                lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS,
993                self.match_lint_level,
994                thir_pat.span,
995                errors::ExclusiveRangeMissingMax {
996                    // Point at this range.
997                    first_range: thir_pat.span,
998                    // That's the gap that isn't covered.
999                    max: gap_as_pat,
1000                    // Suggest `lo..=max` instead.
1001                    suggestion: suggested_range,
1002                },
1003            );
1004        } else {
1005            self.tcx.emit_node_span_lint(
1006                lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS,
1007                self.match_lint_level,
1008                thir_pat.span,
1009                errors::ExclusiveRangeMissingGap {
1010                    // Point at this range.
1011                    first_range: thir_pat.span,
1012                    // That's the gap that isn't covered.
1013                    gap: gap_as_pat.to_string(),
1014                    // Suggest `lo..=gap` instead.
1015                    suggestion: suggested_range,
1016                    // All these ranges skipped over `gap` which we think is probably a
1017                    // mistake.
1018                    gap_with: gapped_with
1019                        .iter()
1020                        .map(|pat| errors::GappedRange {
1021                            span: pat.data().span,
1022                            gap: gap_as_pat.to_string(),
1023                            first_range: range.to_string(),
1024                        })
1025                        .collect(),
1026                },
1027            );
1028        }
1029    }
1030}
1031
1032/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
1033fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
1034    fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
1035        if let PatKind::Or { pats } = &pat.kind {
1036            for pat in pats.iter() {
1037                expand(pat, vec);
1038            }
1039        } else {
1040            vec.push(pat)
1041        }
1042    }
1043
1044    let mut pats = Vec::new();
1045    expand(pat, &mut pats);
1046    pats
1047}
1048
1049/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
1050/// useful, and runs some lints.
1051pub fn analyze_match<'p, 'tcx>(
1052    tycx: &RustcPatCtxt<'p, 'tcx>,
1053    arms: &[MatchArm<'p, 'tcx>],
1054    scrut_ty: Ty<'tcx>,
1055) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
1056    let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
1057
1058    // The analysis doesn't support deref patterns mixed with normal constructors; error if present.
1059    // FIXME(deref_patterns): This only needs to run when a deref pattern was found during lowering.
1060    if tycx.tcx.features().deref_patterns() {
1061        let pat_column = PatternColumn::new(arms);
1062        detect_mixed_deref_pat_ctors(tycx, &pat_column)?;
1063    }
1064
1065    let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee);
1066    let report = compute_match_usefulness(
1067        tycx,
1068        arms,
1069        scrut_ty,
1070        scrut_validity,
1071        tycx.tcx.pattern_complexity_limit().0,
1072    )?;
1073
1074    // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
1075    // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
1076    if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
1077        let pat_column = PatternColumn::new(arms);
1078        lint_nonexhaustive_missing_variants(tycx, arms, &pat_column, scrut_ty)?;
1079    }
1080
1081    Ok(report)
1082}
1083
1084// FIXME(deref_patterns): Currently it's the responsibility of the frontend (rustc or rust-analyzer)
1085// to ensure that deref patterns don't appear in the same column as normal constructors. Deref
1086// patterns aren't currently implemented in rust-analyzer, but should they be, the columnwise check
1087// here could be made generic and shared between frontends.
1088fn detect_mixed_deref_pat_ctors<'p, 'tcx>(
1089    cx: &RustcPatCtxt<'p, 'tcx>,
1090    column: &PatternColumn<'p, RustcPatCtxt<'p, 'tcx>>,
1091) -> Result<(), ErrorGuaranteed> {
1092    let Some(&ty) = column.head_ty() else {
1093        return Ok(());
1094    };
1095
1096    // Check for a mix of deref patterns and normal constructors.
1097    let mut normal_ctor_span = None;
1098    let mut deref_pat_span = None;
1099    for pat in column.iter() {
1100        match pat.ctor() {
1101            // The analysis can handle mixing deref patterns with wildcards and opaque patterns.
1102            Wildcard | Opaque(_) => {}
1103            DerefPattern(_) => deref_pat_span = Some(pat.data().span),
1104            // Nothing else can be compared to deref patterns in `Constructor::is_covered_by`.
1105            _ => normal_ctor_span = Some(pat.data().span),
1106        }
1107    }
1108    if let Some(normal_constructor_label) = normal_ctor_span
1109        && let Some(deref_pattern_label) = deref_pat_span
1110    {
1111        return Err(cx.tcx.dcx().emit_err(errors::MixedDerefPatternConstructors {
1112            spans: vec![deref_pattern_label, normal_constructor_label],
1113            smart_pointer_ty: ty.inner(),
1114            deref_pattern_label,
1115            normal_constructor_label,
1116        }));
1117    }
1118
1119    // Specialize and recurse into the patterns' fields.
1120    let set = column.analyze_ctors(cx, &ty)?;
1121    for ctor in set.present {
1122        for specialized_column in column.specialize(cx, &ty, &ctor).iter() {
1123            detect_mixed_deref_pat_ctors(cx, specialized_column)?;
1124        }
1125    }
1126    Ok(())
1127}