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, VariantDef,
15};
16use rustc_middle::{bug, span_bug};
17use rustc_session::lint;
18use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
19
20use crate::constructor::Constructor::*;
21use crate::constructor::{
22    IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
23};
24use crate::lints::lint_nonexhaustive_missing_variants;
25use crate::pat_column::PatternColumn;
26use crate::rustc::print::EnumInfo;
27use crate::usefulness::{PlaceValidity, compute_match_usefulness};
28use crate::{PatCx, PrivateUninhabitedField, errors};
29
30mod print;
31
32pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcPatCtxt<'p, 'tcx>>;
34pub type ConstructorSet<'p, 'tcx> = crate::constructor::ConstructorSet<RustcPatCtxt<'p, 'tcx>>;
35pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcPatCtxt<'p, 'tcx>>;
36pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcPatCtxt<'p, 'tcx>>;
37pub type RedundancyExplanation<'p, 'tcx> =
38    crate::usefulness::RedundancyExplanation<'p, RustcPatCtxt<'p, 'tcx>>;
39pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcPatCtxt<'p, 'tcx>>;
40pub type UsefulnessReport<'p, 'tcx> =
41    crate::usefulness::UsefulnessReport<'p, RustcPatCtxt<'p, 'tcx>>;
42pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcPatCtxt<'p, 'tcx>>;
43
44#[repr(transparent)]
50#[derive(Clone, Copy, PartialEq, Eq, Hash)]
51pub struct RevealedTy<'tcx>(Ty<'tcx>);
52
53impl<'tcx> fmt::Display for RevealedTy<'tcx> {
54    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
55        self.0.fmt(fmt)
56    }
57}
58
59impl<'tcx> fmt::Debug for RevealedTy<'tcx> {
60    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
61        self.0.fmt(fmt)
62    }
63}
64
65impl<'tcx> std::ops::Deref for RevealedTy<'tcx> {
66    type Target = Ty<'tcx>;
67    fn deref(&self) -> &Self::Target {
68        &self.0
69    }
70}
71
72impl<'tcx> RevealedTy<'tcx> {
73    pub fn inner(self) -> Ty<'tcx> {
74        self.0
75    }
76}
77
78#[derive(Clone)]
79pub struct RustcPatCtxt<'p, 'tcx: 'p> {
80    pub tcx: TyCtxt<'tcx>,
81    pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
82    pub module: DefId,
88    pub typing_env: ty::TypingEnv<'tcx>,
89    pub dropless_arena: &'p DroplessArena,
91    pub match_lint_level: HirId,
93    pub whole_match_span: Option<Span>,
95    pub scrut_span: Span,
97    pub refutable: bool,
99    pub known_valid_scrutinee: bool,
102    pub internal_state: RustcPatCtxtState,
103}
104
105#[derive(Clone, Default)]
107pub struct RustcPatCtxtState {
108    has_lowered_deref_pat: Cell<bool>,
112}
113
114impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        f.debug_struct("RustcPatCtxt").finish()
117    }
118}
119
120impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
121    #[inline]
127    pub fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
128        fn reveal_inner<'tcx>(cx: &RustcPatCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
129            let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!() };
130            if let Some(local_def_id) = alias_ty.def_id.as_local() {
131                let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
132                if let Some(ty) = cx.reveal_opaque_key(key) {
133                    return RevealedTy(ty);
134                }
135            }
136            RevealedTy(ty)
137        }
138        if let ty::Alias(ty::Opaque, _) = ty.kind() {
139            reveal_inner(self, ty)
140        } else {
141            RevealedTy(ty)
142        }
143    }
144
145    fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
148        self.typeck_results
149            .hidden_types
150            .get(&key.def_id)
151            .map(|x| x.ty.instantiate(self.tcx, key.args))
152    }
153    pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
155        !ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
156            self.tcx,
157            self.typing_env,
158            self.module,
159            &|key| self.reveal_opaque_key(key),
160        )
161    }
162
163    pub fn is_foreign_non_exhaustive_enum(&self, ty: RevealedTy<'tcx>) -> bool {
165        match ty.kind() {
166            ty::Adt(def, ..) => def.variant_list_has_applicable_non_exhaustive(),
167            _ => false,
168        }
169    }
170
171    pub fn is_range_beyond_boundaries(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> bool {
174        ty.is_ptr_sized_integral() && {
175            let lo = self.hoist_pat_range_bdy(range.lo, ty);
180            matches!(lo, PatRangeBoundary::PosInfinity)
181                || matches!(range.hi, MaybeInfiniteInt::Finite(0))
182        }
183    }
184
185    pub(crate) fn variant_sub_tys(
186        &self,
187        ty: RevealedTy<'tcx>,
188        variant: &'tcx VariantDef,
189    ) -> impl Iterator<Item = (&'tcx FieldDef, RevealedTy<'tcx>)> {
190        let ty::Adt(_, args) = ty.kind() else { bug!() };
191        variant.fields.iter().map(move |field| {
192            let ty = field.ty(self.tcx, args);
193            let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
195            let ty = self.reveal_opaque_ty(ty);
196            (field, ty)
197        })
198    }
199
200    pub(crate) fn variant_index_for_adt(
201        ctor: &Constructor<'p, 'tcx>,
202        adt: ty::AdtDef<'tcx>,
203    ) -> VariantIdx {
204        match *ctor {
205            Variant(idx) => idx,
206            Struct | UnionField => {
207                assert!(!adt.is_enum());
208                FIRST_VARIANT
209            }
210            _ => bug!("bad constructor {:?} for adt {:?}", ctor, adt),
211        }
212    }
213
214    pub(crate) fn ctor_sub_tys(
217        &self,
218        ctor: &Constructor<'p, 'tcx>,
219        ty: RevealedTy<'tcx>,
220    ) -> impl Iterator<Item = (RevealedTy<'tcx>, PrivateUninhabitedField)> + ExactSizeIterator {
221        fn reveal_and_alloc<'a, 'tcx>(
222            cx: &'a RustcPatCtxt<'_, 'tcx>,
223            iter: impl Iterator<Item = Ty<'tcx>>,
224        ) -> &'a [(RevealedTy<'tcx>, PrivateUninhabitedField)] {
225            cx.dropless_arena.alloc_from_iter(
226                iter.map(|ty| cx.reveal_opaque_ty(ty))
227                    .map(|ty| (ty, PrivateUninhabitedField(false))),
228            )
229        }
230        let cx = self;
231        let slice = match ctor {
232            Struct | Variant(_) | UnionField => match ty.kind() {
233                ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
234                ty::Adt(adt, _) => {
235                    let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
236                    let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
237                        let is_visible =
238                            adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
239                        let is_uninhabited = cx.is_uninhabited(*ty);
240                        let skip = is_uninhabited && !is_visible;
241                        (ty, PrivateUninhabitedField(skip))
242                    });
243                    cx.dropless_arena.alloc_from_iter(tys)
244                }
245                _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
246            },
247            Ref => match ty.kind() {
248                ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)),
249                _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"),
250            },
251            Slice(slice) => match ty.builtin_index() {
252                Some(ty) => {
253                    let arity = slice.arity();
254                    reveal_and_alloc(cx, (0..arity).map(|_| ty))
255                }
256                None => bug!("bad slice pattern {:?} {:?}", ctor, ty),
257            },
258            DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())),
259            Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
260            | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
261            | PrivateUninhabited | Wildcard => &[],
262            Or => {
263                bug!("called `Fields::wildcards` on an `Or` ctor")
264            }
265        };
266        slice.iter().copied()
267    }
268
269    pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: RevealedTy<'tcx>) -> usize {
271        match ctor {
272            Struct | Variant(_) | UnionField => match ty.kind() {
273                ty::Tuple(fs) => fs.len(),
274                ty::Adt(adt, ..) => {
275                    let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
276                    adt.variant(variant_idx).fields.len()
277                }
278                _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
279            },
280            Ref | DerefPattern(_) => 1,
281            Slice(slice) => slice.arity(),
282            Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
283            | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
284            | PrivateUninhabited | Wildcard => 0,
285            Or => bug!("The `Or` constructor doesn't have a fixed arity"),
286        }
287    }
288
289    pub fn ctors_for_ty(
293        &self,
294        ty: RevealedTy<'tcx>,
295    ) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
296        let cx = self;
297        let make_uint_range = |start, end| {
298            IntRange::from_range(
299                MaybeInfiniteInt::new_finite_uint(start),
300                MaybeInfiniteInt::new_finite_uint(end),
301                RangeEnd::Included,
302            )
303        };
304        ty.error_reported()?;
306        Ok(match ty.kind() {
309            ty::Bool => ConstructorSet::Bool,
310            ty::Char => {
311                ConstructorSet::Integers {
313                    range_1: make_uint_range('\u{0000}' as u128, '\u{D7FF}' as u128),
314                    range_2: Some(make_uint_range('\u{E000}' as u128, '\u{10FFFF}' as u128)),
315                }
316            }
317            &ty::Int(ity) => {
318                let range = if ty.is_ptr_sized_integral() {
319                    IntRange {
321                        lo: MaybeInfiniteInt::NegInfinity,
322                        hi: MaybeInfiniteInt::PosInfinity,
323                    }
324                } else {
325                    let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
326                    let min = 1u128 << (size - 1);
327                    let max = min - 1;
328                    let min = MaybeInfiniteInt::new_finite_int(min, size);
329                    let max = MaybeInfiniteInt::new_finite_int(max, size);
330                    IntRange::from_range(min, max, RangeEnd::Included)
331                };
332                ConstructorSet::Integers { range_1: range, range_2: None }
333            }
334            &ty::Uint(uty) => {
335                let range = if ty.is_ptr_sized_integral() {
336                    let lo = MaybeInfiniteInt::new_finite_uint(0);
338                    IntRange { lo, hi: MaybeInfiniteInt::PosInfinity }
339                } else {
340                    let size = Integer::from_uint_ty(&cx.tcx, uty).size();
341                    let max = size.truncate(u128::MAX);
342                    make_uint_range(0, max)
343                };
344                ConstructorSet::Integers { range_1: range, range_2: None }
345            }
346            ty::Slice(sub_ty) => ConstructorSet::Slice {
347                array_len: None,
348                subtype_is_empty: cx.is_uninhabited(*sub_ty),
349            },
350            ty::Array(sub_ty, len) => {
351                ConstructorSet::Slice {
353                    array_len: len.try_to_target_usize(cx.tcx).map(|l| l as usize),
354                    subtype_is_empty: cx.is_uninhabited(*sub_ty),
355                }
356            }
357            ty::Adt(def, args) if def.is_enum() => {
358                let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty);
359                if def.variants().is_empty() && !is_declared_nonexhaustive {
360                    ConstructorSet::NoConstructors
361                } else {
362                    let mut variants =
363                        IndexVec::from_elem(VariantVisibility::Visible, def.variants());
364                    for (idx, v) in def.variants().iter_enumerated() {
365                        let variant_def_id = def.variant(idx).def_id;
366                        let is_inhabited = v
368                            .inhabited_predicate(cx.tcx, *def)
369                            .instantiate(cx.tcx, args)
370                            .apply_revealing_opaque(cx.tcx, cx.typing_env, cx.module, &|key| {
371                                cx.reveal_opaque_key(key)
372                            });
373                        let is_unstable = matches!(
375                            cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None),
376                            EvalResult::Deny { .. }
377                        );
378                        let is_doc_hidden =
380                            cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
381                        let visibility = if !is_inhabited {
382                            VariantVisibility::Empty
384                        } else if is_unstable || is_doc_hidden {
385                            VariantVisibility::Hidden
386                        } else {
387                            VariantVisibility::Visible
388                        };
389                        variants[idx] = visibility;
390                    }
391
392                    ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
393                }
394            }
395            ty::Adt(def, _) if def.is_union() => ConstructorSet::Union,
396            ty::Adt(..) | ty::Tuple(..) => {
397                ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) }
398            }
399            ty::Ref(..) => ConstructorSet::Ref,
400            ty::Never => ConstructorSet::NoConstructors,
401            ty::Float(_)
404            | ty::Str
405            | ty::Foreign(_)
406            | ty::RawPtr(_, _)
407            | ty::FnDef(_, _)
408            | ty::FnPtr(..)
409            | ty::Pat(_, _)
410            | ty::Dynamic(_, _)
411            | ty::Closure(..)
412            | ty::CoroutineClosure(..)
413            | ty::Coroutine(_, _)
414            | ty::UnsafeBinder(_)
415            | ty::Alias(_, _)
416            | ty::Param(_)
417            | ty::Error(_) => ConstructorSet::Unlistable,
418            ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
419                bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
420            }
421        })
422    }
423
424    pub(crate) fn lower_pat_range_bdy(
425        &self,
426        bdy: PatRangeBoundary<'tcx>,
427        ty: RevealedTy<'tcx>,
428    ) -> MaybeInfiniteInt {
429        match bdy {
430            PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity,
431            PatRangeBoundary::Finite(value) => {
432                let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked();
433                match *ty.kind() {
434                    ty::Int(ity) => {
435                        let size = Integer::from_int_ty(&self.tcx, ity).size().bits();
436                        MaybeInfiniteInt::new_finite_int(bits, size)
437                    }
438                    _ => MaybeInfiniteInt::new_finite_uint(bits),
439                }
440            }
441            PatRangeBoundary::PosInfinity => MaybeInfiniteInt::PosInfinity,
442        }
443    }
444
445    pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
448        let cx = self;
449        let ty = cx.reveal_opaque_ty(pat.ty);
450        let ctor;
451        let arity;
452        let fields: Vec<_>;
453        match &pat.kind {
454            PatKind::AscribeUserType { subpattern, .. }
455            | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
456            PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
457            PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
458                ctor = Wildcard;
459                fields = vec![];
460                arity = 0;
461            }
462            PatKind::Deref { subpattern } => {
463                fields = vec![self.lower_pat(subpattern).at_index(0)];
464                arity = 1;
465                ctor = match ty.kind() {
466                    ty::Ref(..) => Ref,
467                    _ => span_bug!(
468                        pat.span,
469                        "pattern has unexpected type: pat: {:?}, ty: {:?}",
470                        pat.kind,
471                        ty.inner()
472                    ),
473                };
474            }
475            PatKind::DerefPattern { subpattern, .. } => {
476                fields = vec![self.lower_pat(subpattern).at_index(0)];
482                arity = 1;
483                ctor = DerefPattern(cx.reveal_opaque_ty(subpattern.ty));
484                self.internal_state.has_lowered_deref_pat.set(true);
485            }
486            PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
487                match ty.kind() {
488                    ty::Tuple(fs) => {
489                        ctor = Struct;
490                        arity = fs.len();
491                        fields = subpatterns
492                            .iter()
493                            .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
494                            .collect();
495                    }
496                    ty::Adt(adt, _) => {
497                        ctor = match pat.kind {
498                            PatKind::Leaf { .. } if adt.is_union() => UnionField,
499                            PatKind::Leaf { .. } => Struct,
500                            PatKind::Variant { variant_index, .. } => Variant(variant_index),
501                            _ => bug!(),
502                        };
503                        let variant =
504                            &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
505                        arity = variant.fields.len();
506                        fields = subpatterns
507                            .iter()
508                            .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
509                            .collect();
510                    }
511                    _ => span_bug!(
512                        pat.span,
513                        "pattern has unexpected type: pat: {:?}, ty: {}",
514                        pat.kind,
515                        ty.inner()
516                    ),
517                }
518            }
519            PatKind::Constant { value } => {
520                match ty.kind() {
521                    ty::Bool => {
522                        ctor = Bool(value.try_to_bool().unwrap());
523                        fields = vec![];
524                        arity = 0;
525                    }
526                    ty::Char | ty::Int(_) | ty::Uint(_) => {
527                        ctor = {
528                            let bits = value.valtree.unwrap_leaf().to_bits_unchecked();
529                            let x = match *ty.kind() {
530                                ty::Int(ity) => {
531                                    let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
532                                    MaybeInfiniteInt::new_finite_int(bits, size)
533                                }
534                                _ => MaybeInfiniteInt::new_finite_uint(bits),
535                            };
536                            IntRange(IntRange::from_singleton(x))
537                        };
538                        fields = vec![];
539                        arity = 0;
540                    }
541                    ty::Float(ty::FloatTy::F16) => {
542                        use rustc_apfloat::Float;
543                        let bits = value.valtree.unwrap_leaf().to_u16();
544                        let value = rustc_apfloat::ieee::Half::from_bits(bits.into());
545                        ctor = F16Range(value, value, RangeEnd::Included);
546                        fields = vec![];
547                        arity = 0;
548                    }
549                    ty::Float(ty::FloatTy::F32) => {
550                        use rustc_apfloat::Float;
551                        let bits = value.valtree.unwrap_leaf().to_u32();
552                        let value = rustc_apfloat::ieee::Single::from_bits(bits.into());
553                        ctor = F32Range(value, value, RangeEnd::Included);
554                        fields = vec![];
555                        arity = 0;
556                    }
557                    ty::Float(ty::FloatTy::F64) => {
558                        use rustc_apfloat::Float;
559                        let bits = value.valtree.unwrap_leaf().to_u64();
560                        let value = rustc_apfloat::ieee::Double::from_bits(bits.into());
561                        ctor = F64Range(value, value, RangeEnd::Included);
562                        fields = vec![];
563                        arity = 0;
564                    }
565                    ty::Float(ty::FloatTy::F128) => {
566                        use rustc_apfloat::Float;
567                        let bits = value.valtree.unwrap_leaf().to_u128();
568                        let value = rustc_apfloat::ieee::Quad::from_bits(bits);
569                        ctor = F128Range(value, value, RangeEnd::Included);
570                        fields = vec![];
571                        arity = 0;
572                    }
573                    ty::Ref(_, t, _) if t.is_str() => {
574                        let ty = self.reveal_opaque_ty(*t);
582                        let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat);
583                        ctor = Ref;
584                        fields = vec![subpattern.at_index(0)];
585                        arity = 1;
586                    }
587                    _ => {
591                        ctor = Opaque(OpaqueId::new());
592                        fields = vec![];
593                        arity = 0;
594                    }
595                }
596            }
597            PatKind::Range(patrange) => {
598                let PatRange { lo, hi, end, .. } = patrange.as_ref();
599                let end = match end {
600                    rustc_hir::RangeEnd::Included => RangeEnd::Included,
601                    rustc_hir::RangeEnd::Excluded => RangeEnd::Excluded,
602                };
603                ctor = match ty.kind() {
604                    ty::Char | ty::Int(_) | ty::Uint(_) => {
605                        let lo = cx.lower_pat_range_bdy(*lo, ty);
606                        let hi = cx.lower_pat_range_bdy(*hi, ty);
607                        IntRange(IntRange::from_range(lo, hi, end))
608                    }
609                    ty::Float(fty) => {
610                        use rustc_apfloat::Float;
611                        let lo = lo
612                            .as_finite()
613                            .map(|c| c.try_to_scalar_int().unwrap().to_bits_unchecked());
614                        let hi = hi
615                            .as_finite()
616                            .map(|c| c.try_to_scalar_int().unwrap().to_bits_unchecked());
617                        match fty {
618                            ty::FloatTy::F16 => {
619                                use rustc_apfloat::ieee::Half;
620                                let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY);
621                                let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY);
622                                F16Range(lo, hi, end)
623                            }
624                            ty::FloatTy::F32 => {
625                                use rustc_apfloat::ieee::Single;
626                                let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY);
627                                let hi = hi.map(Single::from_bits).unwrap_or(Single::INFINITY);
628                                F32Range(lo, hi, end)
629                            }
630                            ty::FloatTy::F64 => {
631                                use rustc_apfloat::ieee::Double;
632                                let lo = lo.map(Double::from_bits).unwrap_or(-Double::INFINITY);
633                                let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY);
634                                F64Range(lo, hi, end)
635                            }
636                            ty::FloatTy::F128 => {
637                                use rustc_apfloat::ieee::Quad;
638                                let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY);
639                                let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY);
640                                F128Range(lo, hi, end)
641                            }
642                        }
643                    }
644                    _ => span_bug!(pat.span, "invalid type for range pattern: {}", ty.inner()),
645                };
646                fields = vec![];
647                arity = 0;
648            }
649            PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
650                let array_len = match ty.kind() {
651                    ty::Array(_, length) => Some(
652                        length
653                            .try_to_target_usize(cx.tcx)
654                            .expect("expected len of array pat to be definite")
655                            as usize,
656                    ),
657                    ty::Slice(_) => None,
658                    _ => span_bug!(pat.span, "bad ty {} for slice pattern", ty.inner()),
659                };
660                let kind = if slice.is_some() {
661                    SliceKind::VarLen(prefix.len(), suffix.len())
662                } else {
663                    SliceKind::FixedLen(prefix.len() + suffix.len())
664                };
665                ctor = Slice(Slice::new(array_len, kind));
666                fields = prefix
667                    .iter()
668                    .chain(suffix.iter())
669                    .map(|p| self.lower_pat(&*p))
670                    .enumerate()
671                    .map(|(i, p)| p.at_index(i))
672                    .collect();
673                arity = kind.arity();
674            }
675            PatKind::Or { .. } => {
676                ctor = Or;
677                let pats = expand_or_pat(pat);
678                fields = pats
679                    .into_iter()
680                    .map(|p| self.lower_pat(p))
681                    .enumerate()
682                    .map(|(i, p)| p.at_index(i))
683                    .collect();
684                arity = fields.len();
685            }
686            PatKind::Never => {
687                ctor = Wildcard;
691                fields = vec![];
692                arity = 0;
693            }
694            PatKind::Error(_) => {
695                ctor = Opaque(OpaqueId::new());
696                fields = vec![];
697                arity = 0;
698            }
699        }
700        DeconstructedPat::new(ctor, fields, arity, ty, pat)
701    }
702
703    fn hoist_pat_range_bdy(
708        &self,
709        miint: MaybeInfiniteInt,
710        ty: RevealedTy<'tcx>,
711    ) -> PatRangeBoundary<'tcx> {
712        use MaybeInfiniteInt::*;
713        let tcx = self.tcx;
714        match miint {
715            NegInfinity => PatRangeBoundary::NegInfinity,
716            Finite(_) => {
717                let size = ty.primitive_size(tcx);
718                let bits = match *ty.kind() {
719                    ty::Int(_) => miint.as_finite_int(size.bits()).unwrap(),
720                    _ => miint.as_finite_uint().unwrap(),
721                };
722                match ScalarInt::try_from_uint(bits, size) {
723                    Some(scalar) => {
724                        let valtree = ty::ValTree::from_scalar_int(tcx, scalar);
725                        PatRangeBoundary::Finite(valtree)
726                    }
727                    None => PatRangeBoundary::PosInfinity,
731                }
732            }
733            PosInfinity => PatRangeBoundary::PosInfinity,
734        }
735    }
736
737    fn print_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> String {
739        use MaybeInfiniteInt::*;
740        let cx = self;
741        if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
742            "_".to_string()
743        } else if range.is_singleton() {
744            let lo = cx.hoist_pat_range_bdy(range.lo, ty);
745            let value = ty::Value { ty: ty.inner(), valtree: lo.as_finite().unwrap() };
746            value.to_string()
747        } else {
748            let mut end = rustc_hir::RangeEnd::Included;
750            let mut lo = cx.hoist_pat_range_bdy(range.lo, ty);
751            if matches!(lo, PatRangeBoundary::PosInfinity) {
752                let max = ty.numeric_max_val(cx.tcx).unwrap();
758                let max = ty::ValTree::from_scalar_int(cx.tcx, max.try_to_scalar_int().unwrap());
759                lo = PatRangeBoundary::Finite(max);
760            }
761            let hi = if let Some(hi) = range.hi.minus_one() {
762                hi
763            } else {
764                end = rustc_hir::RangeEnd::Excluded;
766                range.hi
767            };
768            let hi = cx.hoist_pat_range_bdy(hi, ty);
769            PatRange { lo, hi, end, ty: ty.inner() }.to_string()
770        }
771    }
772
773    pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
777        let cx = self;
778        let print = |p| cx.print_witness_pat(p);
779        match pat.ctor() {
780            Bool(b) => b.to_string(),
781            Str(s) => s.to_string(),
782            IntRange(range) => return self.print_pat_range(range, *pat.ty()),
783            Struct | Variant(_) | UnionField => {
784                let enum_info = match *pat.ty().kind() {
785                    ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
786                        adt_def,
787                        variant_index: RustcPatCtxt::variant_index_for_adt(pat.ctor(), adt_def),
788                    },
789                    ty::Adt(..) | ty::Tuple(..) => EnumInfo::NotEnum,
790                    _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()),
791                };
792
793                let subpatterns = pat
794                    .iter_fields()
795                    .enumerate()
796                    .map(|(i, pat)| print::FieldPat {
797                        field: FieldIdx::new(i),
798                        pattern: print(pat),
799                        is_wildcard: would_print_as_wildcard(cx.tcx, pat),
800                    })
801                    .collect::<Vec<_>>();
802
803                let mut s = String::new();
804                print::write_struct_like(
805                    &mut s,
806                    self.tcx,
807                    pat.ty().inner(),
808                    &enum_info,
809                    &subpatterns,
810                )
811                .unwrap();
812                s
813            }
814            Ref => {
815                let mut s = String::new();
816                print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
817                s
818            }
819            DerefPattern(_) if pat.ty().is_box() && !self.tcx.features().deref_patterns() => {
820                format!("box {}", print(&pat.fields[0]))
826            }
827            DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])),
828            Slice(slice) => {
829                let (prefix_len, has_dot_dot) = match slice.kind {
830                    SliceKind::FixedLen(len) => (len, false),
831                    SliceKind::VarLen(prefix_len, _) => (prefix_len, true),
832                };
833
834                let (mut prefix, mut suffix) = pat.fields.split_at(prefix_len);
835
836                if has_dot_dot && slice.array_len.is_some() {
842                    while let [rest @ .., last] = prefix
843                        && would_print_as_wildcard(cx.tcx, last)
844                    {
845                        prefix = rest;
846                    }
847                    while let [first, rest @ ..] = suffix
848                        && would_print_as_wildcard(cx.tcx, first)
849                    {
850                        suffix = rest;
851                    }
852                }
853
854                let prefix = prefix.iter().map(print).collect::<Vec<_>>();
855                let suffix = suffix.iter().map(print).collect::<Vec<_>>();
856
857                let mut s = String::new();
858                print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
859                s
860            }
861            Never if self.tcx.features().never_patterns() => "!".to_string(),
862            Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
863            Missing { .. } => bug!(
864                "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
865                `Missing` should have been processed in `apply_constructors`"
866            ),
867            F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
868                bug!("can't convert to pattern: {:?}", pat)
869            }
870        }
871    }
872}
873
874fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool {
876    match p.ctor() {
877        Constructor::IntRange(IntRange {
878            lo: MaybeInfiniteInt::NegInfinity,
879            hi: MaybeInfiniteInt::PosInfinity,
880        })
881        | Constructor::Wildcard
882        | Constructor::NonExhaustive
883        | Constructor::Hidden
884        | Constructor::PrivateUninhabited => true,
885        Constructor::Never if !tcx.features().never_patterns() => true,
886        _ => false,
887    }
888}
889
890impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
891    type Ty = RevealedTy<'tcx>;
892    type Error = ErrorGuaranteed;
893    type VariantIdx = VariantIdx;
894    type StrLit = ty::Value<'tcx>;
895    type ArmData = HirId;
896    type PatData = &'p Pat<'tcx>;
897
898    fn is_exhaustive_patterns_feature_on(&self) -> bool {
899        self.tcx.features().exhaustive_patterns()
900    }
901
902    fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
903        self.ctor_arity(ctor, *ty)
904    }
905    fn ctor_sub_tys(
906        &self,
907        ctor: &crate::constructor::Constructor<Self>,
908        ty: &Self::Ty,
909    ) -> impl Iterator<Item = (Self::Ty, PrivateUninhabitedField)> + ExactSizeIterator {
910        self.ctor_sub_tys(ctor, *ty)
911    }
912    fn ctors_for_ty(
913        &self,
914        ty: &Self::Ty,
915    ) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> {
916        self.ctors_for_ty(*ty)
917    }
918
919    fn write_variant_name(
920        f: &mut fmt::Formatter<'_>,
921        ctor: &crate::constructor::Constructor<Self>,
922        ty: &Self::Ty,
923    ) -> fmt::Result {
924        if let ty::Adt(adt, _) = ty.kind() {
925            let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
926            write!(f, "{}", variant.name)?;
927        }
928        Ok(())
929    }
930
931    fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error {
932        span_bug!(self.scrut_span, "{}", fmt)
933    }
934
935    fn lint_overlapping_range_endpoints(
936        &self,
937        pat: &crate::pat::DeconstructedPat<Self>,
938        overlaps_on: IntRange,
939        overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
940    ) {
941        let overlap_as_pat = self.print_pat_range(&overlaps_on, *pat.ty());
942        let overlaps: Vec<_> = overlaps_with
943            .iter()
944            .map(|pat| pat.data().span)
945            .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span })
946            .collect();
947        let pat_span = pat.data().span;
948        self.tcx.emit_node_span_lint(
949            lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
950            self.match_lint_level,
951            pat_span,
952            errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
953        );
954    }
955
956    fn complexity_exceeded(&self) -> Result<(), Self::Error> {
957        let span = self.whole_match_span.unwrap_or(self.scrut_span);
958        Err(self.tcx.dcx().span_err(span, "reached pattern complexity limit"))
959    }
960
961    fn lint_non_contiguous_range_endpoints(
962        &self,
963        pat: &crate::pat::DeconstructedPat<Self>,
964        gap: IntRange,
965        gapped_with: &[&crate::pat::DeconstructedPat<Self>],
966    ) {
967        let &thir_pat = pat.data();
968        let thir::PatKind::Range(range) = &thir_pat.kind else { return };
969        if range.end != rustc_hir::RangeEnd::Excluded {
971            return;
972        }
973        let suggested_range: String = {
976            let mut suggested_range = PatRange::clone(range);
978            suggested_range.end = rustc_hir::RangeEnd::Included;
979            suggested_range.to_string()
980        };
981        let gap_as_pat = self.print_pat_range(&gap, *pat.ty());
982        if gapped_with.is_empty() {
983            self.tcx.emit_node_span_lint(
985                lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS,
986                self.match_lint_level,
987                thir_pat.span,
988                errors::ExclusiveRangeMissingMax {
989                    first_range: thir_pat.span,
991                    max: gap_as_pat,
993                    suggestion: suggested_range,
995                },
996            );
997        } else {
998            self.tcx.emit_node_span_lint(
999                lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS,
1000                self.match_lint_level,
1001                thir_pat.span,
1002                errors::ExclusiveRangeMissingGap {
1003                    first_range: thir_pat.span,
1005                    gap: gap_as_pat.to_string(),
1007                    suggestion: suggested_range,
1009                    gap_with: gapped_with
1012                        .iter()
1013                        .map(|pat| errors::GappedRange {
1014                            span: pat.data().span,
1015                            gap: gap_as_pat.to_string(),
1016                            first_range: range.to_string(),
1017                        })
1018                        .collect(),
1019                },
1020            );
1021        }
1022    }
1023
1024    fn match_may_contain_deref_pats(&self) -> bool {
1025        self.internal_state.has_lowered_deref_pat.get()
1026    }
1027
1028    fn report_mixed_deref_pat_ctors(
1029        &self,
1030        deref_pat: &crate::pat::DeconstructedPat<Self>,
1031        normal_pat: &crate::pat::DeconstructedPat<Self>,
1032    ) -> Self::Error {
1033        let deref_pattern_label = deref_pat.data().span;
1034        let normal_constructor_label = normal_pat.data().span;
1035        self.tcx.dcx().emit_err(errors::MixedDerefPatternConstructors {
1036            spans: vec![deref_pattern_label, normal_constructor_label],
1037            smart_pointer_ty: deref_pat.ty().inner(),
1038            deref_pattern_label,
1039            normal_constructor_label,
1040        })
1041    }
1042}
1043
1044fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
1046    fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
1047        if let PatKind::Or { pats } = &pat.kind {
1048            for pat in pats.iter() {
1049                expand(pat, vec);
1050            }
1051        } else {
1052            vec.push(pat)
1053        }
1054    }
1055
1056    let mut pats = Vec::new();
1057    expand(pat, &mut pats);
1058    pats
1059}
1060
1061pub fn analyze_match<'p, 'tcx>(
1064    tycx: &RustcPatCtxt<'p, 'tcx>,
1065    arms: &[MatchArm<'p, 'tcx>],
1066    scrut_ty: Ty<'tcx>,
1067) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
1068    let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
1069
1070    let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee);
1071    let report = compute_match_usefulness(
1072        tycx,
1073        arms,
1074        scrut_ty,
1075        scrut_validity,
1076        tycx.tcx.pattern_complexity_limit().0,
1077    )?;
1078
1079    if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
1082        let pat_column = PatternColumn::new(arms);
1083        lint_nonexhaustive_missing_variants(tycx, arms, &pat_column, scrut_ty)?;
1084    }
1085
1086    Ok(report)
1087}