rustc_mir_build/builder/matches/
match_pair.rs1use std::sync::Arc;
2
3use rustc_abi::FieldIdx;
4use rustc_middle::mir::*;
5use rustc_middle::span_bug;
6use rustc_middle::thir::*;
7use rustc_middle::ty::{self, Ty, TypeVisitableExt};
8
9use crate::builder::Builder;
10use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
11use crate::builder::matches::{
12 FlatPat, MatchPairTree, PatConstKind, PatternExtraData, SliceLenOp, TestableCase,
13};
14
15impl<'a, 'tcx> Builder<'a, 'tcx> {
16 fn field_match_pairs(
22 &mut self,
23 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
24 extra_data: &mut PatternExtraData<'tcx>,
25 place: PlaceBuilder<'tcx>,
26 subpatterns: &[FieldPat<'tcx>],
27 ) {
28 for fieldpat in subpatterns {
29 let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
30 MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
31 }
32 }
33
34 fn prefix_slice_suffix(
39 &mut self,
40 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
41 extra_data: &mut PatternExtraData<'tcx>,
42 place: &PlaceBuilder<'tcx>,
43 array_len: Option<u64>,
44 prefix: &[Pat<'tcx>],
45 opt_slice: &Option<Box<Pat<'tcx>>>,
46 suffix: &[Pat<'tcx>],
47 ) {
48 let prefix_len = u64::try_from(prefix.len()).unwrap();
49 let suffix_len = u64::try_from(suffix.len()).unwrap();
50
51 let (min_length, is_array) = match array_len {
57 Some(len) => (len, true),
58 None => (prefix_len + suffix_len, false),
59 };
60
61 for (offset, subpattern) in (0u64..).zip(prefix) {
62 let elem = ProjectionElem::ConstantIndex { offset, min_length, from_end: false };
63 let place = place.clone_project(elem);
64 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
65 }
66
67 if let Some(subslice_pat) = opt_slice {
68 let subslice = place.clone_project(PlaceElem::Subslice {
69 from: prefix_len,
70 to: if is_array { min_length - suffix_len } else { suffix_len },
71 from_end: !is_array,
72 });
73 MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
74 }
75
76 for (end_offset, subpattern) in (1u64..).zip(suffix.iter().rev()) {
77 let elem = ProjectionElem::ConstantIndex {
78 offset: if is_array { min_length - end_offset } else { end_offset },
79 min_length,
80 from_end: !is_array,
81 };
82 let place = place.clone_project(elem);
83 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
84 }
85 }
86}
87
88impl<'tcx> MatchPairTree<'tcx> {
89 pub(super) fn for_pattern(
92 mut place_builder: PlaceBuilder<'tcx>,
93 pattern: &Pat<'tcx>,
94 cx: &mut Builder<'_, 'tcx>,
95 match_pairs: &mut Vec<Self>, extra_data: &mut PatternExtraData<'tcx>, ) {
98 if let Some(resolved) = place_builder.resolve_upvar(cx) {
101 place_builder = resolved;
102 }
103
104 if !cx.tcx.next_trait_solver_globally() {
105 let may_need_cast = match place_builder.base() {
108 PlaceBase::Local(local) => {
109 let ty =
110 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
111 .ty;
112 ty != pattern.ty && ty.has_opaque_types()
113 }
114 _ => true,
115 };
116 if may_need_cast {
117 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
118 }
119 }
120
121 let place = place_builder.try_to_place(cx);
122
123 if let Some(place) = place
125 && let Some(extra) = &pattern.extra
126 {
127 for &Ascription { ref annotation, variance } in &extra.ascriptions {
128 extra_data.ascriptions.push(super::Ascription {
129 source: place,
130 annotation: annotation.clone(),
131 variance,
132 });
133 }
134 }
135
136 let mut subpairs = Vec::new();
137 let testable_case = match pattern.kind {
138 PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
139
140 PatKind::Or { ref pats } => {
141 let pats: Box<[FlatPat<'tcx>]> =
142 pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
143 if !pats[0].extra_data.bindings.is_empty() {
144 extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
150 }
151 Some(TestableCase::Or { pats })
152 }
153
154 PatKind::Range(ref range) => {
155 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);
156 if range.is_full_range(cx.tcx) == Some(true) {
157 None
158 } else {
159 Some(TestableCase::Range(Arc::clone(range)))
160 }
161 }
162
163 PatKind::Constant { value } => {
164 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);
165
166 let pat_ty = pattern.ty;
169 let const_kind = if pat_ty.is_bool() {
170 PatConstKind::Bool
171 } else if pat_ty.is_integral() || pat_ty.is_char() {
172 PatConstKind::IntOrChar
173 } else if pat_ty.is_floating_point() {
174 PatConstKind::Float
175 } else if pat_ty.is_str() {
176 PatConstKind::String
177 } else {
178 PatConstKind::Other
182 };
183 Some(TestableCase::Constant { value, kind: const_kind })
184 }
185
186 PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => {
187 if let Some(subpattern) = subpattern.as_ref() {
208 MatchPairTree::for_pattern(
210 place_builder,
211 subpattern,
212 cx,
213 &mut subpairs,
214 extra_data,
215 );
216 }
217
218 if let Some(source) = place {
220 extra_data.bindings.push(super::SubpatternBindings::One(super::Binding {
221 span: pattern.span,
222 source,
223 var_id: var,
224 binding_mode: mode,
225 is_shorthand,
226 }));
227 }
228
229 None
230 }
231
232 PatKind::Array { ref prefix, ref slice, ref suffix } => {
233 let array_len = match pattern.ty.kind() {
238 ty::Array(_, len) => len.try_to_target_usize(cx.tcx),
239 _ => None,
240 };
241 if let Some(array_len) = array_len {
242 cx.prefix_slice_suffix(
243 &mut subpairs,
244 extra_data,
245 &place_builder,
246 Some(array_len),
247 prefix,
248 slice,
249 suffix,
250 );
251 } else {
252 cx.tcx.dcx().span_delayed_bug(
255 pattern.span,
256 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("array length in pattern couldn\'t be determined for ty={0:?}",
pattern.ty))
})format!(
257 "array length in pattern couldn't be determined for ty={:?}",
258 pattern.ty
259 ),
260 );
261 }
262
263 None
264 }
265 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
266 cx.prefix_slice_suffix(
267 &mut subpairs,
268 extra_data,
269 &place_builder,
270 None,
271 prefix,
272 slice,
273 suffix,
274 );
275
276 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
277 None
280 } else {
281 Some(TestableCase::Slice {
285 len: u64::try_from(prefix.len() + suffix.len()).unwrap(),
286 op: if slice.is_some() {
287 SliceLenOp::GreaterOrEqual
288 } else {
289 SliceLenOp::Equal
290 },
291 })
292 }
293 }
294
295 PatKind::Variant { adt_def, variant_index, args: _, ref subpatterns } => {
296 let downcast_place = place_builder.downcast(adt_def, variant_index); cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
298
299 let refutable =
302 adt_def.variants().len() > 1 || adt_def.is_variant_list_non_exhaustive();
303 if refutable {
304 Some(TestableCase::Variant { adt_def, variant_index })
305 } else {
306 None
307 }
308 }
309
310 PatKind::Leaf { ref subpatterns } => {
311 cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
312 None
313 }
314
315 PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
316 let pinned_ref_ty = match pattern.ty.pinned_ty() {
317 Some(p_ty) if p_ty.is_ref() => p_ty,
318 _ => ::rustc_middle::util::bug::span_bug_fmt(pattern.span,
format_args!("bad type for pinned deref: {0:?}", pattern.ty))span_bug!(pattern.span, "bad type for pinned deref: {:?}", pattern.ty),
319 };
320 MatchPairTree::for_pattern(
321 place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(),
323 subpattern,
324 cx,
325 &mut subpairs,
326 extra_data,
327 );
328
329 None
330 }
331
332 PatKind::Deref { pin: Pinnedness::Not, ref subpattern }
333 | PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => {
334 MatchPairTree::for_pattern(
335 place_builder.deref(),
336 subpattern,
337 cx,
338 &mut subpairs,
339 extra_data,
340 );
341 None
342 }
343
344 PatKind::DerefPattern {
345 ref subpattern,
346 borrow: DerefPatBorrowMode::Borrow(mutability),
347 } => {
348 let temp = cx.temp(
351 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
352 pattern.span,
353 );
354 MatchPairTree::for_pattern(
355 PlaceBuilder::from(temp).deref(),
356 subpattern,
357 cx,
358 &mut subpairs,
359 extra_data,
360 );
361 Some(TestableCase::Deref { temp, mutability })
362 }
363
364 PatKind::Guard { .. } => {
365 None
367 }
368
369 PatKind::Never => Some(TestableCase::Never),
370 };
371
372 if let Some(testable_case) = testable_case {
373 match_pairs.push(MatchPairTree {
381 place,
382 testable_case,
383 subpairs,
384 pattern_span: pattern.span,
385 })
386 } else {
387 match_pairs.extend(subpairs);
390 }
391 }
392}