Skip to main content

rustc_pattern_analysis/
rustc.rs

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