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