rustc_pattern_analysis/
rustc.rs

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