1use std::sync::Arc;
2
3use rustc_abi::FieldIdx;
4use rustc_middle::mir::{Pinnedness, Place, PlaceElem, ProjectionElem};
5use rustc_middle::thir::{Ascription, DerefPatBorrowMode, FieldPat, Pat, PatKind};
6use rustc_middle::ty::consts::ConstExt;
7use rustc_middle::ty::{self, Ty, TypeVisitableExt};
8use rustc_span::{Span, span_bug};
9
10use crate::builder::Builder;
11use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
12use crate::builder::matches::{
13 FlatPat, MatchPairKind, MatchPairTree, PatConstKind, PatternExtraData, SliceLenOp, TestableCase,
14};
15
16fn prefix_slice_suffix<'a, 'tcx>(
19 place: &PlaceBuilder<'tcx>,
20 array_len: Option<u64>, prefix: &'a [Pat<'tcx>],
22 opt_slice: &'a Option<Box<Pat<'tcx>>>,
23 suffix: &'a [Pat<'tcx>],
24) -> Vec<(PlaceBuilder<'tcx>, &'a Pat<'tcx>)> {
25 let prefix_len = u64::try_from(prefix.len()).unwrap();
26 let suffix_len = u64::try_from(suffix.len()).unwrap();
27
28 let mut output_pairs =
29 Vec::with_capacity(prefix.len() + usize::from(opt_slice.is_some()) + suffix.len());
30
31 let (min_length, is_array) = match array_len {
37 Some(len) => (len, true),
38 None => (prefix_len + suffix_len, false),
39 };
40
41 for (offset, prefix_subpat) in (0u64..).zip(prefix) {
42 let elem = ProjectionElem::ConstantIndex { offset, min_length, from_end: false };
43 let subplace = place.clone_project(elem);
44 output_pairs.push((subplace, prefix_subpat));
45 }
46
47 if let Some(slice_subpat) = opt_slice {
48 let elem = PlaceElem::Subslice {
49 from: prefix_len,
50 to: if is_array { min_length - suffix_len } else { suffix_len },
51 from_end: !is_array,
52 };
53 let subplace = place.clone_project(elem);
54 output_pairs.push((subplace, slice_subpat));
55 }
56
57 for (offset_from_end, suffix_subpat) in (1u64..).zip(suffix.iter().rev()) {
58 let elem = ProjectionElem::ConstantIndex {
59 offset: if is_array { min_length - offset_from_end } else { offset_from_end },
60 min_length,
61 from_end: !is_array,
62 };
63 let subplace = place.clone_project(elem);
64 output_pairs.push((subplace, suffix_subpat));
65 }
66
67 output_pairs
68}
69
70impl<'tcx> FlatPat<'tcx> {
71 pub(crate) fn new(
74 place: PlaceBuilder<'tcx>,
75 pattern: &Pat<'tcx>,
76 cx: &mut Builder<'_, 'tcx>,
77 ) -> Self {
78 let inter_pat = InterPat::lower_thir_pat(cx, place, pattern);
81 FlatPat::from_inter_pat(inter_pat)
82 }
83
84 fn from_inter_pat(inter_pat: InterPat<'tcx>) -> Self {
89 let mut match_pairs = ::alloc::vec::Vec::new()vec![];
90 let mut extra_data = PatternExtraData {
91 span: inter_pat.pattern_span,
92 bindings: ::alloc::vec::Vec::new()vec![],
93 ascriptions: ::alloc::vec::Vec::new()vec![],
94 is_never: inter_pat.is_never,
95 };
96 squash_inter_pat(inter_pat, &mut match_pairs, &mut extra_data);
97
98 FlatPat { match_pairs, extra_data }
99 }
100}
101
102fn squash_inter_pat<'tcx>(
105 inter_pat: InterPat<'tcx>,
106 match_pairs: &mut Vec<MatchPairTree<'tcx>>, extra_data: &mut PatternExtraData<'tcx>, ) {
109 let InterPat { kind, ascriptions, pattern_span, is_never: _ } = inter_pat;
112
113 extra_data.ascriptions.extend(ascriptions);
115
116 match kind {
118 InterPatKind::Or { or_subpats } => {
119 let or_subpats = or_subpats
120 .into_iter()
121 .map(|subpat| FlatPat::from_inter_pat(subpat))
122 .collect::<Box<[_]>>();
123
124 if !or_subpats[0].extra_data.bindings.is_empty() {
125 extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
131 }
132
133 match_pairs
134 .push(MatchPairTree { kind: MatchPairKind::Or { or_subpats }, pattern_span });
135 }
136
137 InterPatKind::Refutable { place, testable_case, subpats } => {
138 let mut subpairs = ::alloc::vec::Vec::new()vec![];
141 for subpat in subpats {
142 squash_inter_pat(subpat, &mut subpairs, extra_data);
143 }
144
145 match_pairs.push(MatchPairTree {
147 kind: MatchPairKind::Testable { place, testable_case, subpairs },
148 pattern_span,
149 });
150 }
151
152 InterPatKind::Irrefutable { subpats, binding } => {
153 for subpat in subpats {
156 squash_inter_pat(subpat, match_pairs, extra_data);
158 }
159
160 if let Some(binding) = binding {
165 extra_data.bindings.push(super::SubpatternBindings::One(binding));
166 }
167 }
168 }
169}
170
171struct InterPat<'tcx> {
174 kind: InterPatKind<'tcx>,
175
176 ascriptions: Vec<super::Ascription<'tcx>>,
177 pattern_span: Span,
179 is_never: bool,
182}
183
184enum InterPatKind<'tcx> {
185 Or {
186 or_subpats: Box<[InterPat<'tcx>]>,
188 },
189
190 Refutable {
192 place: Place<'tcx>,
194 testable_case: TestableCase<'tcx>,
196 subpats: Vec<InterPat<'tcx>>,
198 },
199
200 Irrefutable {
202 subpats: Vec<InterPat<'tcx>>,
204 binding: Option<super::Binding<'tcx>>,
206 },
207}
208
209impl<'tcx> InterPat<'tcx> {
210 fn lower_thir_pat(
211 cx: &mut Builder<'_, 'tcx>,
212 mut place_builder: PlaceBuilder<'tcx>,
213 pattern: &Pat<'tcx>,
214 ) -> Self {
215 if let Some(resolved) = place_builder.resolve_upvar(cx) {
218 place_builder = resolved;
219 }
220
221 if !cx.tcx.next_trait_solver_globally() {
222 let may_need_cast = match place_builder.base() {
225 PlaceBase::Local(local) => {
226 let ty =
227 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
228 .ty;
229 ty != pattern.ty && ty.has_opaque_types()
230 }
231 _ => true,
232 };
233 if may_need_cast {
234 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
235 }
236 }
237
238 let place = place_builder.try_to_place(cx);
239
240 let mut ascriptions = ::alloc::vec::Vec::new()vec![];
242 if let Some(place) = place
243 && let Some(extra) = &pattern.extra
244 {
245 ascriptions.extend(extra.ascriptions.iter().map(
246 |&Ascription { ref annotation, variance }| super::Ascription {
247 source: place,
248 annotation: annotation.clone(),
249 variance,
250 },
251 ));
252 }
253
254 let unwrap_place = || place.expect("refutable patterns must have captured a place");
257
258 let kind: InterPatKind<'_> = match pattern.kind {
259 PatKind::Missing | PatKind::Wild | PatKind::Error(_) => {
260 InterPatKind::Irrefutable { subpats: ::alloc::vec::Vec::new()vec![], binding: None }
261 }
262
263 PatKind::Or { ref pats } => {
264 let or_subpats = pats
265 .iter()
266 .map(|subpat| InterPat::lower_thir_pat(cx, place_builder.clone(), subpat))
267 .collect::<Box<[_]>>();
268 InterPatKind::Or { or_subpats }
269 }
270
271 PatKind::Range(ref range) => {
272 {
match (&pattern.ty, &range.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(pattern.ty, range.ty);
273 if range.is_full_range(cx.tcx) == Some(true) {
274 InterPatKind::Irrefutable { subpats: ::alloc::vec::Vec::new()vec![], binding: None }
275 } else {
276 InterPatKind::Refutable {
277 place: unwrap_place(),
278 testable_case: TestableCase::Range(Arc::clone(range)),
279 subpats: ::alloc::vec::Vec::new()vec![],
280 }
281 }
282 }
283
284 PatKind::Constant { value } => {
285 {
match (&pattern.ty, &value.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(pattern.ty, value.ty);
286
287 let pat_ty = pattern.ty;
290 let const_kind = if pat_ty.is_bool() {
291 PatConstKind::Bool
292 } else if pat_ty.is_integral() || pat_ty.is_char() {
293 PatConstKind::IntOrChar
294 } else if pat_ty.is_floating_point() {
295 PatConstKind::Float
296 } else if pat_ty.is_str() {
297 PatConstKind::String
298 } else {
299 PatConstKind::Other
303 };
304
305 InterPatKind::Refutable {
306 place: unwrap_place(),
307 testable_case: TestableCase::Constant { value, kind: const_kind },
308 subpats: ::alloc::vec::Vec::new()vec![],
309 }
310 }
311
312 PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => {
313 let subpat: Option<InterPat<'_>> = subpattern
316 .as_deref()
317 .map(|subpattern| InterPat::lower_thir_pat(cx, place_builder, subpattern));
318
319 let binding = place.map(|place| super::Binding {
321 span: pattern.span,
322 source: place,
323 var_id: var,
324 binding_mode: mode,
325 is_shorthand,
326 });
327 InterPatKind::Irrefutable { subpats: Vec::from_iter(subpat), binding }
328 }
329
330 PatKind::Array { ref prefix, ref slice, ref suffix } => {
331 let array_len = match pattern.ty.kind() {
336 ty::Array(_, len) => len.try_to_target_usize(cx.tcx),
337 _ => None,
338 };
339
340 let mut subpats = ::alloc::vec::Vec::new()vec![];
341 if let Some(array_len) = array_len {
342 for (subplace, subpat) in
343 prefix_slice_suffix(&place_builder, Some(array_len), prefix, slice, suffix)
344 {
345 subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat));
346 }
347 } else {
348 cx.tcx.dcx().span_delayed_bug(
351 pattern.span,
352 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("array length in pattern couldn\'t be determined for ty={0:?}",
pattern.ty))
})format!(
353 "array length in pattern couldn't be determined for ty={:?}",
354 pattern.ty
355 ),
356 );
357 }
358
359 InterPatKind::Irrefutable { subpats, binding: None }
360 }
361 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
362 let mut subpats = ::alloc::vec::Vec::new()vec![];
363 for (subplace, subpat) in
364 prefix_slice_suffix(&place_builder, None, prefix, slice, suffix)
365 {
366 subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat));
367 }
368
369 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
370 InterPatKind::Irrefutable { subpats, binding: None }
373 } else {
374 let testable_case = TestableCase::Slice {
378 len: u64::try_from(prefix.len() + suffix.len()).unwrap(),
379 op: if slice.is_some() {
380 SliceLenOp::GreaterOrEqual
381 } else {
382 SliceLenOp::Equal
383 },
384 };
385 InterPatKind::Refutable { place: unwrap_place(), testable_case, subpats }
386 }
387 }
388
389 PatKind::Variant { adt_def, variant_index, args: _, ref subpatterns } => {
390 let downcast_place = place_builder.downcast(adt_def, variant_index); let mut subpats = ::alloc::vec::Vec::new()vec![];
392 for &FieldPat { field, pattern: ref subpat } in subpatterns {
393 let subplace = downcast_place.clone_project(PlaceElem::Field(field, subpat.ty));
394 subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat));
395 }
396
397 let refutable =
400 adt_def.variants().len() > 1 || adt_def.is_variant_list_non_exhaustive();
401 if refutable {
402 let testable_case = TestableCase::Variant { adt_def, variant_index };
403 InterPatKind::Refutable { place: unwrap_place(), testable_case, subpats }
404 } else {
405 InterPatKind::Irrefutable { subpats, binding: None }
406 }
407 }
408
409 PatKind::Leaf { ref subpatterns } => {
410 let mut subpats = ::alloc::vec::Vec::new()vec![];
411 for &FieldPat { field, pattern: ref subpat } in subpatterns {
412 let subplace = place_builder.clone_project(PlaceElem::Field(field, subpat.ty));
413 subpats.push(InterPat::lower_thir_pat(cx, subplace, subpat));
414 }
415 InterPatKind::Irrefutable { subpats, binding: None }
416 }
417
418 PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
419 let pinned_ref_ty = match pattern.ty.pinned_ty() {
420 Some(p_ty) if p_ty.is_ref() => p_ty,
421 _ => ::rustc_span::macros::bug_impl(Some(pattern.span),
format_args!("bad type for pinned deref: {0:?}", pattern.ty),
Location::caller())span_bug!(pattern.span, "bad type for pinned deref: {:?}", pattern.ty),
422 };
423 let subpat = InterPat::lower_thir_pat(
424 cx,
425 place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(),
427 subpattern,
428 );
429
430 InterPatKind::Irrefutable { subpats: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[subpat]))vec![subpat], binding: None }
431 }
432
433 PatKind::Deref { pin: Pinnedness::Not, ref subpattern }
434 | PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => {
435 let subpat = InterPat::lower_thir_pat(cx, place_builder.deref(), subpattern);
436 InterPatKind::Irrefutable { subpats: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[subpat]))vec![subpat], binding: None }
437 }
438
439 PatKind::DerefPattern {
440 ref subpattern,
441 borrow: DerefPatBorrowMode::Borrow(mutability),
442 } => {
443 let temp = cx.temp(
446 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
447 pattern.span,
448 );
449 let subpat =
450 InterPat::lower_thir_pat(cx, PlaceBuilder::from(temp).deref(), subpattern);
451 InterPatKind::Refutable {
452 place: unwrap_place(),
453 testable_case: TestableCase::Deref { temp, mutability },
454 subpats: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[subpat]))vec![subpat],
455 }
456 }
457
458 PatKind::Guard { .. } => {
459 InterPatKind::Irrefutable { subpats: ::alloc::vec::Vec::new()vec![], binding: None }
461 }
462
463 PatKind::Never => InterPatKind::Refutable {
464 place: unwrap_place(),
465 testable_case: TestableCase::Never,
466 subpats: ::alloc::vec::Vec::new()vec![],
467 },
468 };
469
470 let is_never = match &kind {
475 InterPatKind::Refutable { testable_case: TestableCase::Never, .. } => true,
476 InterPatKind::Refutable { subpats, .. } | InterPatKind::Irrefutable { subpats, .. } => {
477 subpats.iter().any(|subpat| subpat.is_never)
478 }
479 InterPatKind::Or { or_subpats } => or_subpats.iter().all(|subpat| subpat.is_never),
480 };
481
482 InterPat { kind, ascriptions, pattern_span: pattern.span, is_never }
483 }
484}