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