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