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