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
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> MatchPairTree<'tcx> {
70 pub(super) fn for_pattern(
73 mut place_builder: PlaceBuilder<'tcx>,
74 pattern: &Pat<'tcx>,
75 cx: &mut Builder<'_, 'tcx>,
76 match_pairs: &mut Vec<Self>, extra_data: &mut PatternExtraData<'tcx>, ) {
79 if let Some(resolved) = place_builder.resolve_upvar(cx) {
82 place_builder = resolved;
83 }
84
85 if !cx.tcx.next_trait_solver_globally() {
86 let may_need_cast = match place_builder.base() {
89 PlaceBase::Local(local) => {
90 let ty =
91 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
92 .ty;
93 ty != pattern.ty && ty.has_opaque_types()
94 }
95 _ => true,
96 };
97 if may_need_cast {
98 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
99 }
100 }
101
102 let place = place_builder.try_to_place(cx);
103
104 if let Some(place) = place
106 && let Some(extra) = &pattern.extra
107 {
108 for &Ascription { ref annotation, variance } in &extra.ascriptions {
109 extra_data.ascriptions.push(super::Ascription {
110 source: place,
111 annotation: annotation.clone(),
112 variance,
113 });
114 }
115 }
116
117 let mut subpairs = Vec::new();
118 let testable_case = match pattern.kind {
119 PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
120
121 PatKind::Or { ref pats } => {
122 let pats: Box<[FlatPat<'tcx>]> =
123 pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
124 if !pats[0].extra_data.bindings.is_empty() {
125 extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
131 }
132 Some(TestableCase::Or { pats })
133 }
134
135 PatKind::Range(ref range) => {
136 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);
137 if range.is_full_range(cx.tcx) == Some(true) {
138 None
139 } else {
140 Some(TestableCase::Range(Arc::clone(range)))
141 }
142 }
143
144 PatKind::Constant { value } => {
145 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);
146
147 let pat_ty = pattern.ty;
150 let const_kind = if pat_ty.is_bool() {
151 PatConstKind::Bool
152 } else if pat_ty.is_integral() || pat_ty.is_char() {
153 PatConstKind::IntOrChar
154 } else if pat_ty.is_floating_point() {
155 PatConstKind::Float
156 } else if pat_ty.is_str() {
157 PatConstKind::String
158 } else {
159 PatConstKind::Other
163 };
164 Some(TestableCase::Constant { value, kind: const_kind })
165 }
166
167 PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => {
168 if let Some(subpattern) = subpattern.as_ref() {
189 MatchPairTree::for_pattern(
191 place_builder,
192 subpattern,
193 cx,
194 &mut subpairs,
195 extra_data,
196 );
197 }
198
199 if let Some(source) = place {
201 extra_data.bindings.push(super::SubpatternBindings::One(super::Binding {
202 span: pattern.span,
203 source,
204 var_id: var,
205 binding_mode: mode,
206 is_shorthand,
207 }));
208 }
209
210 None
211 }
212
213 PatKind::Array { ref prefix, ref slice, ref suffix } => {
214 let array_len = match pattern.ty.kind() {
219 ty::Array(_, len) => len.try_to_target_usize(cx.tcx),
220 _ => None,
221 };
222 if let Some(array_len) = array_len {
223 for (subplace, subpat) in
224 prefix_slice_suffix(&place_builder, Some(array_len), prefix, slice, suffix)
225 {
226 MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data);
227 }
228 } else {
229 cx.tcx.dcx().span_delayed_bug(
232 pattern.span,
233 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("array length in pattern couldn\'t be determined for ty={0:?}",
pattern.ty))
})format!(
234 "array length in pattern couldn't be determined for ty={:?}",
235 pattern.ty
236 ),
237 );
238 }
239
240 None
241 }
242 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
243 for (subplace, subpat) in
244 prefix_slice_suffix(&place_builder, None, prefix, slice, suffix)
245 {
246 MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data);
247 }
248
249 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
250 None
253 } else {
254 Some(TestableCase::Slice {
258 len: u64::try_from(prefix.len() + suffix.len()).unwrap(),
259 op: if slice.is_some() {
260 SliceLenOp::GreaterOrEqual
261 } else {
262 SliceLenOp::Equal
263 },
264 })
265 }
266 }
267
268 PatKind::Variant { adt_def, variant_index, args: _, ref subpatterns } => {
269 let downcast_place = place_builder.downcast(adt_def, variant_index); for &FieldPat { field, pattern: ref subpat } in subpatterns {
271 let subplace = downcast_place.clone_project(PlaceElem::Field(field, subpat.ty));
272 MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data);
273 }
274
275 let refutable =
278 adt_def.variants().len() > 1 || adt_def.is_variant_list_non_exhaustive();
279 if refutable {
280 Some(TestableCase::Variant { adt_def, variant_index })
281 } else {
282 None
283 }
284 }
285
286 PatKind::Leaf { ref subpatterns } => {
287 for &FieldPat { field, pattern: ref subpat } in subpatterns {
288 let subplace = place_builder.clone_project(PlaceElem::Field(field, subpat.ty));
289 MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data);
290 }
291 None
292 }
293
294 PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
295 let pinned_ref_ty = match pattern.ty.pinned_ty() {
296 Some(p_ty) if p_ty.is_ref() => p_ty,
297 _ => ::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),
298 };
299 MatchPairTree::for_pattern(
300 place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(),
302 subpattern,
303 cx,
304 &mut subpairs,
305 extra_data,
306 );
307
308 None
309 }
310
311 PatKind::Deref { pin: Pinnedness::Not, ref subpattern }
312 | PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => {
313 MatchPairTree::for_pattern(
314 place_builder.deref(),
315 subpattern,
316 cx,
317 &mut subpairs,
318 extra_data,
319 );
320 None
321 }
322
323 PatKind::DerefPattern {
324 ref subpattern,
325 borrow: DerefPatBorrowMode::Borrow(mutability),
326 } => {
327 let temp = cx.temp(
330 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
331 pattern.span,
332 );
333 MatchPairTree::for_pattern(
334 PlaceBuilder::from(temp).deref(),
335 subpattern,
336 cx,
337 &mut subpairs,
338 extra_data,
339 );
340 Some(TestableCase::Deref { temp, mutability })
341 }
342
343 PatKind::Guard { .. } => {
344 None
346 }
347
348 PatKind::Never => Some(TestableCase::Never),
349 };
350
351 if let Some(testable_case) = testable_case {
352 match_pairs.push(MatchPairTree {
360 place,
361 testable_case,
362 subpairs,
363 pattern_span: pattern.span,
364 })
365 } else {
366 match_pairs.extend(subpairs);
369 }
370 }
371}