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(#[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)]
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(#[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)]
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(#[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)]
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 { ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))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 #[allow(non_exhaustive_omitted_patterns)] match lo {
PatRangeBoundary::PosInfinity => true,
_ => false,
}matches!(lo, PatRangeBoundary::PosInfinity)
181 || #[allow(non_exhaustive_omitted_patterns)] match range.hi {
MaybeInfiniteInt::Finite(0) => true,
_ => false,
}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 { ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!() };
191 variant.fields.iter().map(move |field| {
192 let ty = field.ty(self.tcx, args);
193 let ty =
195 self.tcx.try_normalize_erasing_regions(self.typing_env, ty).unwrap_or_else(|e| {
196 self.tcx.dcx().span_delayed_bug(
197 self.scrut_span,
198 ::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!(
199 "Failed to normalize {:?} in typing_env={:?} while getting variant sub tys for {ty:?}",
200 e.get_type_for_failure(),
201 self.typing_env,
202 ),
203 );
204 ty
205 });
206 let ty = self.reveal_opaque_ty(ty);
207 (field, ty)
208 })
209 }
210
211 pub(crate) fn variant_index_for_adt(
212 ctor: &Constructor<'p, 'tcx>,
213 adt: ty::AdtDef<'tcx>,
214 ) -> VariantIdx {
215 match *ctor {
216 Variant(idx) => idx,
217 Struct | UnionField => {
218 if !!adt.is_enum() {
::core::panicking::panic("assertion failed: !adt.is_enum()")
};assert!(!adt.is_enum());
219 FIRST_VARIANT
220 }
221 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("bad constructor {0:?} for adt {1:?}",
ctor, adt))bug!("bad constructor {:?} for adt {:?}", ctor, adt),
222 }
223 }
224
225 pub(crate) fn ctor_sub_tys(
228 &self,
229 ctor: &Constructor<'p, 'tcx>,
230 ty: RevealedTy<'tcx>,
231 ) -> impl Iterator<Item = (RevealedTy<'tcx>, PrivateUninhabitedField)> + ExactSizeIterator {
232 fn reveal_and_alloc<'a, 'tcx>(
233 cx: &'a RustcPatCtxt<'_, 'tcx>,
234 iter: impl Iterator<Item = Ty<'tcx>>,
235 ) -> &'a [(RevealedTy<'tcx>, PrivateUninhabitedField)] {
236 cx.dropless_arena.alloc_from_iter(
237 iter.map(|ty| cx.reveal_opaque_ty(ty))
238 .map(|ty| (ty, PrivateUninhabitedField(false))),
239 )
240 }
241 let cx = self;
242 let slice = match ctor {
243 Struct | Variant(_) | UnionField => match ty.kind() {
244 ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
245 ty::Adt(adt, _) => {
246 let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
247 let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
248 let is_visible =
249 adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
250 let is_uninhabited = cx.is_uninhabited(*ty);
251 let skip = is_uninhabited && !is_visible;
252 (ty, PrivateUninhabitedField(skip))
253 });
254 cx.dropless_arena.alloc_from_iter(tys)
255 }
256 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected type for constructor `{0:?}`: {1:?}",
ctor, ty))bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
257 },
258 Ref => match ty.kind() {
259 ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)),
260 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected type for `Ref` constructor: {0:?}",
ty))bug!("Unexpected type for `Ref` constructor: {ty:?}"),
261 },
262 Slice(slice) => match ty.builtin_index() {
263 Some(ty) => {
264 let arity = slice.arity();
265 reveal_and_alloc(cx, (0..arity).map(|_| ty))
266 }
267 None => ::rustc_middle::util::bug::bug_fmt(format_args!("bad slice pattern {0:?} {1:?}",
ctor, ty))bug!("bad slice pattern {:?} {:?}", ctor, ty),
268 },
269 DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())),
270 Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
271 | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
272 | PrivateUninhabited | Wildcard => &[],
273 Or => {
274 ::rustc_middle::util::bug::bug_fmt(format_args!("called `Fields::wildcards` on an `Or` ctor"))bug!("called `Fields::wildcards` on an `Or` ctor")
275 }
276 };
277 slice.iter().copied()
278 }
279
280 pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: RevealedTy<'tcx>) -> usize {
282 match ctor {
283 Struct | Variant(_) | UnionField => match ty.kind() {
284 ty::Tuple(fs) => fs.len(),
285 ty::Adt(adt, ..) => {
286 let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
287 adt.variant(variant_idx).fields.len()
288 }
289 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected type for constructor `{0:?}`: {1:?}",
ctor, ty))bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
290 },
291 Ref | DerefPattern(_) => 1,
292 Slice(slice) => slice.arity(),
293 Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
294 | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
295 | PrivateUninhabited | Wildcard => 0,
296 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"),
297 }
298 }
299
300 pub fn ctors_for_ty(
304 &self,
305 ty: RevealedTy<'tcx>,
306 ) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
307 let cx = self;
308 let make_uint_range = |start, end| {
309 IntRange::from_range(
310 MaybeInfiniteInt::new_finite_uint(start),
311 MaybeInfiniteInt::new_finite_uint(end),
312 RangeEnd::Included,
313 )
314 };
315 ty.error_reported()?;
317 Ok(match ty.kind() {
320 ty::Bool => ConstructorSet::Bool,
321 ty::Char => {
322 ConstructorSet::Integers {
324 range_1: make_uint_range('\u{0000}' as u128, '\u{D7FF}' as u128),
325 range_2: Some(make_uint_range('\u{E000}' as u128, '\u{10FFFF}' as u128)),
326 }
327 }
328 &ty::Int(ity) => {
329 let range = if ty.is_ptr_sized_integral() {
330 IntRange {
332 lo: MaybeInfiniteInt::NegInfinity,
333 hi: MaybeInfiniteInt::PosInfinity,
334 }
335 } else {
336 let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
337 let min = 1u128 << (size - 1);
338 let max = min - 1;
339 let min = MaybeInfiniteInt::new_finite_int(min, size);
340 let max = MaybeInfiniteInt::new_finite_int(max, size);
341 IntRange::from_range(min, max, RangeEnd::Included)
342 };
343 ConstructorSet::Integers { range_1: range, range_2: None }
344 }
345 &ty::Uint(uty) => {
346 let range = if ty.is_ptr_sized_integral() {
347 let lo = MaybeInfiniteInt::new_finite_uint(0);
349 IntRange { lo, hi: MaybeInfiniteInt::PosInfinity }
350 } else {
351 let size = Integer::from_uint_ty(&cx.tcx, uty).size();
352 let max = size.truncate(u128::MAX);
353 make_uint_range(0, max)
354 };
355 ConstructorSet::Integers { range_1: range, range_2: None }
356 }
357 ty::Slice(sub_ty) => ConstructorSet::Slice {
358 array_len: None,
359 subtype_is_empty: cx.is_uninhabited(*sub_ty),
360 },
361 ty::Array(sub_ty, len) => {
362 ConstructorSet::Slice {
364 array_len: len.try_to_target_usize(cx.tcx).map(|l| l as usize),
365 subtype_is_empty: cx.is_uninhabited(*sub_ty),
366 }
367 }
368 ty::Adt(def, args) if def.is_enum() => {
369 let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty);
370 if def.variants().is_empty() && !is_declared_nonexhaustive {
371 ConstructorSet::NoConstructors
372 } else {
373 let mut variants =
374 IndexVec::from_elem(VariantVisibility::Visible, def.variants());
375 for (idx, v) in def.variants().iter_enumerated() {
376 let variant_def_id = def.variant(idx).def_id;
377 let is_inhabited = v
379 .inhabited_predicate(cx.tcx, *def)
380 .instantiate(cx.tcx, args)
381 .apply_revealing_opaque(cx.tcx, cx.typing_env, cx.module, &|key| {
382 cx.reveal_opaque_key(key)
383 });
384 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!(
386 cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None),
387 EvalResult::Deny { .. }
388 );
389 let is_doc_hidden =
391 cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
392 let visibility = if !is_inhabited {
393 VariantVisibility::Empty
395 } else if is_unstable || is_doc_hidden {
396 VariantVisibility::Hidden
397 } else {
398 VariantVisibility::Visible
399 };
400 variants[idx] = visibility;
401 }
402
403 ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
404 }
405 }
406 ty::Adt(def, _) if def.is_union() => ConstructorSet::Union,
407 ty::Adt(..) | ty::Tuple(..) => {
408 ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) }
409 }
410 ty::Ref(..) => ConstructorSet::Ref,
411 ty::Never => ConstructorSet::NoConstructors,
412 ty::Float(_)
415 | ty::Str
416 | ty::Foreign(_)
417 | ty::RawPtr(_, _)
418 | ty::FnDef(_, _)
419 | ty::FnPtr(..)
420 | ty::Pat(_, _)
421 | ty::Dynamic(_, _)
422 | ty::Closure(..)
423 | ty::CoroutineClosure(..)
424 | ty::Coroutine(_, _)
425 | ty::UnsafeBinder(_)
426 | ty::Alias(_, _)
427 | ty::Param(_)
428 | ty::Error(_) => ConstructorSet::Unlistable,
429 ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
430 ::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:?}")
431 }
432 })
433 }
434
435 pub(crate) fn lower_pat_range_bdy(
436 &self,
437 bdy: PatRangeBoundary<'tcx>,
438 ty: RevealedTy<'tcx>,
439 ) -> MaybeInfiniteInt {
440 match bdy {
441 PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity,
442 PatRangeBoundary::Finite(value) => {
443 let bits = value.to_leaf().to_bits_unchecked();
444 match *ty.kind() {
445 ty::Int(ity) => {
446 let size = Integer::from_int_ty(&self.tcx, ity).size().bits();
447 MaybeInfiniteInt::new_finite_int(bits, size)
448 }
449 _ => MaybeInfiniteInt::new_finite_uint(bits),
450 }
451 }
452 PatRangeBoundary::PosInfinity => MaybeInfiniteInt::PosInfinity,
453 }
454 }
455
456 pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
459 let cx = self;
460 let ty = cx.reveal_opaque_ty(pat.ty);
461 let ctor;
462 let arity;
463 let fields: Vec<_>;
464 match &pat.kind {
465 PatKind::Binding { subpattern: Some(subpat), .. }
466 | PatKind::Guard { subpattern: subpat, .. } => return self.lower_pat(subpat),
467 PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
468 ctor = Wildcard;
469 fields = ::alloc::vec::Vec::new()vec![];
470 arity = 0;
471 }
472 PatKind::Deref { pin, subpattern } => {
473 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)];
474 arity = 1;
475 ctor = match (pin, ty.maybe_pinned_ref()) {
476 (ty::Pinnedness::Not, Some((_, ty::Pinnedness::Not, _, _))) => Ref,
477 (ty::Pinnedness::Pinned, Some((inner_ty, ty::Pinnedness::Pinned, _, _))) => {
478 self.internal_state.has_lowered_deref_pat.set(true);
479 DerefPattern(RevealedTy(inner_ty))
480 }
481 _ => ::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!(
482 pat.span,
483 "pattern has unexpected type: pat: {:?}, ty: {:?}",
484 pat.kind,
485 ty.inner()
486 ),
487 };
488 }
489 PatKind::DerefPattern { subpattern, .. } => {
490 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)];
496 arity = 1;
497 ctor = DerefPattern(cx.reveal_opaque_ty(subpattern.ty));
498 self.internal_state.has_lowered_deref_pat.set(true);
499 }
500 PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
501 match ty.kind() {
502 ty::Tuple(fs) => {
503 ctor = Struct;
504 arity = fs.len();
505 fields = subpatterns
506 .iter()
507 .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
508 .collect();
509 }
510 ty::Adt(adt, _) => {
511 ctor = match pat.kind {
512 PatKind::Leaf { .. } if adt.is_union() => UnionField,
513 PatKind::Leaf { .. } => Struct,
514 PatKind::Variant { variant_index, .. } => Variant(variant_index),
515 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
516 };
517 let variant =
518 &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
519 arity = variant.fields.len();
520 fields = subpatterns
521 .iter()
522 .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
523 .collect();
524 }
525 _ => ::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!(
526 pat.span,
527 "pattern has unexpected type: pat: {:?}, ty: {}",
528 pat.kind,
529 ty.inner()
530 ),
531 }
532 }
533 PatKind::Constant { value } => {
534 match ty.kind() {
535 ty::Bool => {
536 ctor = Bool(value.try_to_bool().unwrap());
537 fields = ::alloc::vec::Vec::new()vec![];
538 arity = 0;
539 }
540 ty::Char | ty::Int(_) | ty::Uint(_) => {
541 ctor = {
542 let bits = value.to_leaf().to_bits_unchecked();
543 let x = match *ty.kind() {
544 ty::Int(ity) => {
545 let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
546 MaybeInfiniteInt::new_finite_int(bits, size)
547 }
548 _ => MaybeInfiniteInt::new_finite_uint(bits),
549 };
550 IntRange(IntRange::from_singleton(x))
551 };
552 fields = ::alloc::vec::Vec::new()vec![];
553 arity = 0;
554 }
555 ty::Float(ty::FloatTy::F16) => {
556 use rustc_apfloat::Float;
557 let bits = value.to_leaf().to_u16();
558 let value = rustc_apfloat::ieee::Half::from_bits(bits.into());
559 ctor = F16Range(value, value, RangeEnd::Included);
560 fields = ::alloc::vec::Vec::new()vec![];
561 arity = 0;
562 }
563 ty::Float(ty::FloatTy::F32) => {
564 use rustc_apfloat::Float;
565 let bits = value.to_leaf().to_u32();
566 let value = rustc_apfloat::ieee::Single::from_bits(bits.into());
567 ctor = F32Range(value, value, RangeEnd::Included);
568 fields = ::alloc::vec::Vec::new()vec![];
569 arity = 0;
570 }
571 ty::Float(ty::FloatTy::F64) => {
572 use rustc_apfloat::Float;
573 let bits = value.to_leaf().to_u64();
574 let value = rustc_apfloat::ieee::Double::from_bits(bits.into());
575 ctor = F64Range(value, value, RangeEnd::Included);
576 fields = ::alloc::vec::Vec::new()vec![];
577 arity = 0;
578 }
579 ty::Float(ty::FloatTy::F128) => {
580 use rustc_apfloat::Float;
581 let bits = value.to_leaf().to_u128();
582 let value = rustc_apfloat::ieee::Quad::from_bits(bits);
583 ctor = F128Range(value, value, RangeEnd::Included);
584 fields = ::alloc::vec::Vec::new()vec![];
585 arity = 0;
586 }
587 ty::Str => {
588 ctor = Str(*value);
592 fields = ::alloc::vec::Vec::new()vec![];
593 arity = 0;
594 }
595 _ => {
599 ctor = Opaque(OpaqueId::new());
600 fields = ::alloc::vec::Vec::new()vec![];
601 arity = 0;
602 }
603 }
604 }
605 PatKind::Range(patrange) => {
606 let PatRange { lo, hi, end, .. } = patrange.as_ref();
607 let end = match end {
608 rustc_hir::RangeEnd::Included => RangeEnd::Included,
609 rustc_hir::RangeEnd::Excluded => RangeEnd::Excluded,
610 };
611 ctor = match ty.kind() {
612 ty::Char | ty::Int(_) | ty::Uint(_) => {
613 let lo = cx.lower_pat_range_bdy(*lo, ty);
614 let hi = cx.lower_pat_range_bdy(*hi, ty);
615 IntRange(IntRange::from_range(lo, hi, end))
616 }
617 ty::Float(fty) => {
618 use rustc_apfloat::Float;
619 let lo = lo.as_finite().map(|c| c.to_leaf().to_bits_unchecked());
620 let hi = hi.as_finite().map(|c| c.to_leaf().to_bits_unchecked());
621 match fty {
622 ty::FloatTy::F16 => {
623 use rustc_apfloat::ieee::Half;
624 let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY);
625 let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY);
626 F16Range(lo, hi, end)
627 }
628 ty::FloatTy::F32 => {
629 use rustc_apfloat::ieee::Single;
630 let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY);
631 let hi = hi.map(Single::from_bits).unwrap_or(Single::INFINITY);
632 F32Range(lo, hi, end)
633 }
634 ty::FloatTy::F64 => {
635 use rustc_apfloat::ieee::Double;
636 let lo = lo.map(Double::from_bits).unwrap_or(-Double::INFINITY);
637 let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY);
638 F64Range(lo, hi, end)
639 }
640 ty::FloatTy::F128 => {
641 use rustc_apfloat::ieee::Quad;
642 let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY);
643 let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY);
644 F128Range(lo, hi, end)
645 }
646 }
647 }
648 _ => ::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()),
649 };
650 fields = ::alloc::vec::Vec::new()vec![];
651 arity = 0;
652 }
653 PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
654 let array_len = match ty.kind() {
655 ty::Array(_, length) => Some(
656 length
657 .try_to_target_usize(cx.tcx)
658 .expect("expected len of array pat to be definite")
659 as usize,
660 ),
661 ty::Slice(_) => None,
662 _ => ::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()),
663 };
664 let kind = if slice.is_some() {
665 SliceKind::VarLen(prefix.len(), suffix.len())
666 } else {
667 SliceKind::FixedLen(prefix.len() + suffix.len())
668 };
669 ctor = Slice(Slice::new(array_len, kind));
670 fields = prefix
671 .iter()
672 .chain(suffix.iter())
673 .map(|p| self.lower_pat(&*p))
674 .enumerate()
675 .map(|(i, p)| p.at_index(i))
676 .collect();
677 arity = kind.arity();
678 }
679 PatKind::Or { .. } => {
680 ctor = Or;
681 let pats = expand_or_pat(pat);
682 fields = pats
683 .into_iter()
684 .map(|p| self.lower_pat(p))
685 .enumerate()
686 .map(|(i, p)| p.at_index(i))
687 .collect();
688 arity = fields.len();
689 }
690 PatKind::Never => {
691 ctor = Wildcard;
695 fields = ::alloc::vec::Vec::new()vec![];
696 arity = 0;
697 }
698 PatKind::Error(_) => {
699 ctor = Opaque(OpaqueId::new());
700 fields = ::alloc::vec::Vec::new()vec![];
701 arity = 0;
702 }
703 }
704 DeconstructedPat::new(ctor, fields, arity, ty, pat)
705 }
706
707 fn hoist_pat_range_bdy(
712 &self,
713 miint: MaybeInfiniteInt,
714 ty: RevealedTy<'tcx>,
715 ) -> PatRangeBoundary<'tcx> {
716 use MaybeInfiniteInt::*;
717 let tcx = self.tcx;
718 match miint {
719 NegInfinity => PatRangeBoundary::NegInfinity,
720 Finite(_) => {
721 let size = ty.primitive_size(tcx);
722 let bits = match *ty.kind() {
723 ty::Int(_) => miint.as_finite_int(size.bits()).unwrap(),
724 _ => miint.as_finite_uint().unwrap(),
725 };
726 match ScalarInt::try_from_uint(bits, size) {
727 Some(scalar) => {
728 let valtree = ty::ValTree::from_scalar_int(tcx, scalar);
729 PatRangeBoundary::Finite(valtree)
730 }
731 None => PatRangeBoundary::PosInfinity,
735 }
736 }
737 PosInfinity => PatRangeBoundary::PosInfinity,
738 }
739 }
740
741 fn print_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> String {
743 use MaybeInfiniteInt::*;
744 let cx = self;
745 if #[allow(non_exhaustive_omitted_patterns)] match (range.lo, range.hi) {
(NegInfinity, PosInfinity) => true,
_ => false,
}matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
746 "_".to_string()
747 } else if range.is_singleton() {
748 let lo = cx.hoist_pat_range_bdy(range.lo, ty);
749 let value = ty::Value { ty: ty.inner(), valtree: lo.as_finite().unwrap() };
750 value.to_string()
751 } else {
752 let mut end = rustc_hir::RangeEnd::Included;
754 let mut lo = cx.hoist_pat_range_bdy(range.lo, ty);
755 if #[allow(non_exhaustive_omitted_patterns)] match lo {
PatRangeBoundary::PosInfinity => true,
_ => false,
}matches!(lo, PatRangeBoundary::PosInfinity) {
756 let max = ty.numeric_max_val(cx.tcx).unwrap();
762 let max = ty::ValTree::from_scalar_int(cx.tcx, max.try_to_scalar_int().unwrap());
763 lo = PatRangeBoundary::Finite(max);
764 }
765 let hi = if let Some(hi) = range.hi.minus_one() {
766 hi
767 } else {
768 end = rustc_hir::RangeEnd::Excluded;
770 range.hi
771 };
772 let hi = cx.hoist_pat_range_bdy(hi, ty);
773 PatRange { lo, hi, end, ty: ty.inner() }.to_string()
774 }
775 }
776
777 pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
781 let cx = self;
782 let print = |p| cx.print_witness_pat(p);
783 match pat.ctor() {
784 Bool(b) => b.to_string(),
785 Str(s) => s.to_string(),
786 IntRange(range) => return self.print_pat_range(range, *pat.ty()),
787 Struct | Variant(_) | UnionField => {
788 let enum_info = match *pat.ty().kind() {
789 ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
790 adt_def,
791 variant_index: RustcPatCtxt::variant_index_for_adt(pat.ctor(), adt_def),
792 },
793 ty::Adt(..) | ty::Tuple(..) => EnumInfo::NotEnum,
794 _ => ::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()),
795 };
796
797 let subpatterns = pat
798 .iter_fields()
799 .enumerate()
800 .map(|(i, pat)| print::FieldPat {
801 field: FieldIdx::new(i),
802 pattern: print(pat),
803 is_wildcard: would_print_as_wildcard(cx.tcx, pat),
804 })
805 .collect::<Vec<_>>();
806
807 let mut s = String::new();
808 print::write_struct_like(
809 &mut s,
810 self.tcx,
811 pat.ty().inner(),
812 &enum_info,
813 &subpatterns,
814 )
815 .unwrap();
816 s
817 }
818 Ref => {
819 let mut s = String::new();
820 print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
821 s
822 }
823 DerefPattern(_) if pat.ty().is_box() && !self.tcx.features().deref_patterns() => {
824 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("box {0}", print(&pat.fields[0])))
})format!("box {}", print(&pat.fields[0]))
830 }
831 DerefPattern(_) => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("deref!({0})",
print(&pat.fields[0])))
})format!("deref!({})", print(&pat.fields[0])),
832 Slice(slice) => {
833 let (prefix_len, has_dot_dot) = match slice.kind {
834 SliceKind::FixedLen(len) => (len, false),
835 SliceKind::VarLen(prefix_len, _) => (prefix_len, true),
836 };
837
838 let (mut prefix, mut suffix) = pat.fields.split_at(prefix_len);
839
840 if has_dot_dot && slice.array_len.is_some() {
846 while let [rest @ .., last] = prefix
847 && would_print_as_wildcard(cx.tcx, last)
848 {
849 prefix = rest;
850 }
851 while let [first, rest @ ..] = suffix
852 && would_print_as_wildcard(cx.tcx, first)
853 {
854 suffix = rest;
855 }
856 }
857
858 let prefix = prefix.iter().map(print).collect::<Vec<_>>();
859 let suffix = suffix.iter().map(print).collect::<Vec<_>>();
860
861 let mut s = String::new();
862 print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
863 s
864 }
865 Never if self.tcx.features().never_patterns() => "!".to_string(),
866 Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
867 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!(
868 "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
869 `Missing` should have been processed in `apply_constructors`"
870 ),
871 F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
872 ::rustc_middle::util::bug::bug_fmt(format_args!("can\'t convert to pattern: {0:?}",
pat))bug!("can't convert to pattern: {:?}", pat)
873 }
874 }
875 }
876}
877
878fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool {
880 match p.ctor() {
881 Constructor::IntRange(IntRange {
882 lo: MaybeInfiniteInt::NegInfinity,
883 hi: MaybeInfiniteInt::PosInfinity,
884 })
885 | Constructor::Wildcard
886 | Constructor::NonExhaustive
887 | Constructor::Hidden
888 | Constructor::PrivateUninhabited => true,
889 Constructor::Never if !tcx.features().never_patterns() => true,
890 _ => false,
891 }
892}
893
894impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
895 type Ty = RevealedTy<'tcx>;
896 type Error = ErrorGuaranteed;
897 type VariantIdx = VariantIdx;
898 type StrLit = ty::Value<'tcx>;
899 type ArmData = HirId;
900 type PatData = &'p Pat<'tcx>;
901
902 fn is_exhaustive_patterns_feature_on(&self) -> bool {
903 self.tcx.features().exhaustive_patterns()
904 }
905
906 fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
907 self.ctor_arity(ctor, *ty)
908 }
909 fn ctor_sub_tys(
910 &self,
911 ctor: &crate::constructor::Constructor<Self>,
912 ty: &Self::Ty,
913 ) -> impl Iterator<Item = (Self::Ty, PrivateUninhabitedField)> + ExactSizeIterator {
914 self.ctor_sub_tys(ctor, *ty)
915 }
916 fn ctors_for_ty(
917 &self,
918 ty: &Self::Ty,
919 ) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> {
920 self.ctors_for_ty(*ty)
921 }
922
923 fn write_variant_name(
924 f: &mut fmt::Formatter<'_>,
925 ctor: &crate::constructor::Constructor<Self>,
926 ty: &Self::Ty,
927 ) -> fmt::Result {
928 if let ty::Adt(adt, _) = ty.kind() {
929 let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
930 f.write_fmt(format_args!("{0}", variant.name))write!(f, "{}", variant.name)?;
931 }
932 Ok(())
933 }
934
935 fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error {
936 ::rustc_middle::util::bug::span_bug_fmt(self.scrut_span,
format_args!("{0}", fmt))span_bug!(self.scrut_span, "{}", fmt)
937 }
938
939 fn lint_overlapping_range_endpoints(
940 &self,
941 pat: &crate::pat::DeconstructedPat<Self>,
942 overlaps_on: IntRange,
943 overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
944 ) {
945 let overlap_as_pat = self.print_pat_range(&overlaps_on, *pat.ty());
946 let overlaps: Vec<_> = overlaps_with
947 .iter()
948 .map(|pat| pat.data().span)
949 .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span })
950 .collect();
951 let pat_span = pat.data().span;
952 self.tcx.emit_node_span_lint(
953 lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
954 self.match_lint_level,
955 pat_span,
956 errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
957 );
958 }
959
960 fn complexity_exceeded(&self) -> Result<(), Self::Error> {
961 let span = self.whole_match_span.unwrap_or(self.scrut_span);
962 Err(self.tcx.dcx().span_err(span, "reached pattern complexity limit"))
963 }
964
965 fn lint_non_contiguous_range_endpoints(
966 &self,
967 pat: &crate::pat::DeconstructedPat<Self>,
968 gap: IntRange,
969 gapped_with: &[&crate::pat::DeconstructedPat<Self>],
970 ) {
971 let &thir_pat = pat.data();
972 let thir::PatKind::Range(range) = &thir_pat.kind else { return };
973 if range.end != rustc_hir::RangeEnd::Excluded {
975 return;
976 }
977 let suggested_range: String = {
980 let mut suggested_range = PatRange::clone(range);
982 suggested_range.end = rustc_hir::RangeEnd::Included;
983 suggested_range.to_string()
984 };
985 let gap_as_pat = self.print_pat_range(&gap, *pat.ty());
986 if gapped_with.is_empty() {
987 self.tcx.emit_node_span_lint(
989 lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS,
990 self.match_lint_level,
991 thir_pat.span,
992 errors::ExclusiveRangeMissingMax {
993 first_range: thir_pat.span,
995 max: gap_as_pat,
997 suggestion: suggested_range,
999 },
1000 );
1001 } else {
1002 self.tcx.emit_node_span_lint(
1003 lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS,
1004 self.match_lint_level,
1005 thir_pat.span,
1006 errors::ExclusiveRangeMissingGap {
1007 first_range: thir_pat.span,
1009 gap: gap_as_pat.to_string(),
1011 suggestion: suggested_range,
1013 gap_with: gapped_with
1016 .iter()
1017 .map(|pat| errors::GappedRange {
1018 span: pat.data().span,
1019 gap: gap_as_pat.to_string(),
1020 first_range: range.to_string(),
1021 })
1022 .collect(),
1023 },
1024 );
1025 }
1026 }
1027
1028 fn match_may_contain_deref_pats(&self) -> bool {
1029 self.internal_state.has_lowered_deref_pat.get()
1030 }
1031
1032 fn report_mixed_deref_pat_ctors(
1033 &self,
1034 deref_pat: &crate::pat::DeconstructedPat<Self>,
1035 normal_pat: &crate::pat::DeconstructedPat<Self>,
1036 ) -> Self::Error {
1037 let deref_pattern_label = deref_pat.data().span;
1038 let normal_constructor_label = normal_pat.data().span;
1039 self.tcx.dcx().emit_err(errors::MixedDerefPatternConstructors {
1040 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],
1041 smart_pointer_ty: deref_pat.ty().inner(),
1042 deref_pattern_label,
1043 normal_constructor_label,
1044 })
1045 }
1046}
1047
1048fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
1050 fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
1051 if let PatKind::Or { pats } = &pat.kind {
1052 for pat in pats.iter() {
1053 expand(pat, vec);
1054 }
1055 } else {
1056 vec.push(pat)
1057 }
1058 }
1059
1060 let mut pats = Vec::new();
1061 expand(pat, &mut pats);
1062 pats
1063}
1064
1065pub fn analyze_match<'p, 'tcx>(
1068 tycx: &RustcPatCtxt<'p, 'tcx>,
1069 arms: &[MatchArm<'p, 'tcx>],
1070 scrut_ty: Ty<'tcx>,
1071) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
1072 let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
1073
1074 let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee);
1075 let report = compute_match_usefulness(
1076 tycx,
1077 arms,
1078 scrut_ty,
1079 scrut_validity,
1080 tycx.tcx.pattern_complexity_limit().0,
1081 )?;
1082
1083 if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
1086 let pat_column = PatternColumn::new(arms);
1087 lint_nonexhaustive_missing_variants(tycx, arms, &pat_column, scrut_ty)?;
1088 }
1089
1090 Ok(report)
1091}