rustc_mir_build/builder/matches/
match_pair.rs1use std::sync::Arc;
2
3use rustc_abi::FieldIdx;
4use rustc_hir::ByRef;
5use rustc_middle::mir::*;
6use rustc_middle::thir::*;
7use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};
8
9use crate::builder::Builder;
10use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
11use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
12
13impl<'a, 'tcx> Builder<'a, 'tcx> {
14 fn field_match_pairs(
20 &mut self,
21 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
22 extra_data: &mut PatternExtraData<'tcx>,
23 place: PlaceBuilder<'tcx>,
24 subpatterns: &[FieldPat<'tcx>],
25 ) {
26 for fieldpat in subpatterns {
27 let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
28 MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
29 }
30 }
31
32 fn prefix_slice_suffix(
37 &mut self,
38 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
39 extra_data: &mut PatternExtraData<'tcx>,
40 place: &PlaceBuilder<'tcx>,
41 prefix: &[Pat<'tcx>],
42 opt_slice: &Option<Box<Pat<'tcx>>>,
43 suffix: &[Pat<'tcx>],
44 ) {
45 let tcx = self.tcx;
46 let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
47 let place_ty = place_resolved.ty(&self.local_decls, tcx).ty;
48 match place_ty.kind() {
49 ty::Array(_, length) => {
50 if let Some(length) = length.try_to_target_usize(tcx) {
51 (length, true)
52 } else {
53 tcx.dcx().span_delayed_bug(
58 tcx.def_span(self.def_id),
59 "array length in pattern couldn't be evaluated",
60 );
61 ((prefix.len() + suffix.len()).try_into().unwrap(), false)
62 }
63 }
64 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
65 }
66 } else {
67 ((prefix.len() + suffix.len()).try_into().unwrap(), false)
68 };
69
70 for (idx, subpattern) in prefix.iter().enumerate() {
71 let elem =
72 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
73 let place = place.clone_project(elem);
74 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
75 }
76
77 if let Some(subslice_pat) = opt_slice {
78 let suffix_len = suffix.len() as u64;
79 let subslice = place.clone_project(PlaceElem::Subslice {
80 from: prefix.len() as u64,
81 to: if exact_size { min_length - suffix_len } else { suffix_len },
82 from_end: !exact_size,
83 });
84 MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
85 }
86
87 for (idx, subpattern) in suffix.iter().rev().enumerate() {
88 let end_offset = (idx + 1) as u64;
89 let elem = ProjectionElem::ConstantIndex {
90 offset: if exact_size { min_length - end_offset } else { end_offset },
91 min_length,
92 from_end: !exact_size,
93 };
94 let place = place.clone_project(elem);
95 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
96 }
97 }
98}
99
100impl<'tcx> MatchPairTree<'tcx> {
101 pub(super) fn for_pattern(
104 mut place_builder: PlaceBuilder<'tcx>,
105 pattern: &Pat<'tcx>,
106 cx: &mut Builder<'_, 'tcx>,
107 match_pairs: &mut Vec<Self>, extra_data: &mut PatternExtraData<'tcx>, ) {
110 if let Some(resolved) = place_builder.resolve_upvar(cx) {
113 place_builder = resolved;
114 }
115
116 if !cx.tcx.next_trait_solver_globally() {
117 let may_need_cast = match place_builder.base() {
120 PlaceBase::Local(local) => {
121 let ty =
122 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
123 .ty;
124 ty != pattern.ty && ty.has_opaque_types()
125 }
126 _ => true,
127 };
128 if may_need_cast {
129 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
130 }
131 }
132
133 let place = place_builder.try_to_place(cx);
134 let mut subpairs = Vec::new();
135 let test_case = match pattern.kind {
136 PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
137
138 PatKind::Or { ref pats } => {
139 let pats: Box<[FlatPat<'tcx>]> =
140 pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
141 if !pats[0].extra_data.bindings.is_empty() {
142 extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
148 }
149 Some(TestCase::Or { pats })
150 }
151
152 PatKind::Range(ref range) => {
153 if range.is_full_range(cx.tcx) == Some(true) {
154 None
155 } else {
156 Some(TestCase::Range(Arc::clone(range)))
157 }
158 }
159
160 PatKind::Constant { value } => Some(TestCase::Constant { value }),
161
162 PatKind::AscribeUserType {
163 ascription: Ascription { ref annotation, variance },
164 ref subpattern,
165 ..
166 } => {
167 MatchPairTree::for_pattern(
168 place_builder,
169 subpattern,
170 cx,
171 &mut subpairs,
172 extra_data,
173 );
174
175 if let Some(source) = place {
177 let annotation = annotation.clone();
178 extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
179 }
180
181 None
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::ExpandedConstant { subpattern: ref pattern, .. } => {
231 MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
232 None
233 }
234
235 PatKind::Array { ref prefix, ref slice, ref suffix } => {
236 cx.prefix_slice_suffix(
237 &mut subpairs,
238 extra_data,
239 &place_builder,
240 prefix,
241 slice,
242 suffix,
243 );
244 None
245 }
246 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
247 cx.prefix_slice_suffix(
248 &mut subpairs,
249 extra_data,
250 &place_builder,
251 prefix,
252 slice,
253 suffix,
254 );
255
256 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
257 None
258 } else {
259 Some(TestCase::Slice {
260 len: prefix.len() + suffix.len(),
261 variable_length: slice.is_some(),
262 })
263 }
264 }
265
266 PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
267 let downcast_place = place_builder.downcast(adt_def, variant_index); cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
269
270 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
271 i == variant_index
272 || !v.inhabited_predicate(cx.tcx, adt_def).instantiate(cx.tcx, args).apply(
273 cx.tcx,
274 cx.infcx.typing_env(cx.param_env),
275 cx.def_id.into(),
276 )
277 }) && !adt_def.variant_list_has_applicable_non_exhaustive();
278 if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
279 }
280
281 PatKind::Leaf { ref subpatterns } => {
282 cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
283 None
284 }
285
286 PatKind::Deref { ref subpattern }
287 | PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) }
288 if let Some(ref_ty) = pattern.ty.pinned_ty()
289 && ref_ty.is_ref() =>
290 {
291 MatchPairTree::for_pattern(
292 place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
293 subpattern,
294 cx,
295 &mut subpairs,
296 extra_data,
297 );
298 None
299 }
300
301 PatKind::DerefPattern { borrow: ByRef::Yes(Pinnedness::Pinned, _), .. } => {
302 rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty)
303 }
304
305 PatKind::Deref { ref subpattern }
306 | PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
307 MatchPairTree::for_pattern(
308 place_builder.deref(),
309 subpattern,
310 cx,
311 &mut subpairs,
312 extra_data,
313 );
314 None
315 }
316
317 PatKind::DerefPattern {
318 ref subpattern,
319 borrow: ByRef::Yes(Pinnedness::Not, mutability),
320 } => {
321 let temp = cx.temp(
324 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
325 pattern.span,
326 );
327 MatchPairTree::for_pattern(
328 PlaceBuilder::from(temp).deref(),
329 subpattern,
330 cx,
331 &mut subpairs,
332 extra_data,
333 );
334 Some(TestCase::Deref { temp, mutability })
335 }
336
337 PatKind::Never => Some(TestCase::Never),
338 };
339
340 if let Some(test_case) = test_case {
341 match_pairs.push(MatchPairTree {
343 place,
344 test_case,
345 subpairs,
346 pattern_ty: pattern.ty,
347 pattern_span: pattern.span,
348 })
349 } else {
350 match_pairs.extend(subpairs);
353 }
354 }
355}