rustc_mir_build/builder/matches/
match_pair.rs1use std::sync::Arc;
2
3use rustc_middle::mir::*;
4use rustc_middle::thir::*;
5use rustc_middle::ty::{self, Ty, TypeVisitableExt};
6
7use crate::builder::Builder;
8use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
9use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
10
11impl<'a, 'tcx> Builder<'a, 'tcx> {
12 fn field_match_pairs(
18 &mut self,
19 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
20 extra_data: &mut PatternExtraData<'tcx>,
21 place: PlaceBuilder<'tcx>,
22 subpatterns: &[FieldPat<'tcx>],
23 ) {
24 for fieldpat in subpatterns {
25 let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
26 MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
27 }
28 }
29
30 fn prefix_slice_suffix(
35 &mut self,
36 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
37 extra_data: &mut PatternExtraData<'tcx>,
38 place: &PlaceBuilder<'tcx>,
39 prefix: &[Pat<'tcx>],
40 opt_slice: &Option<Box<Pat<'tcx>>>,
41 suffix: &[Pat<'tcx>],
42 ) {
43 let tcx = self.tcx;
44 let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
45 match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
46 ty::Array(_, length) => (
47 length
48 .try_to_target_usize(tcx)
49 .expect("expected len of array pat to be definite"),
50 true,
51 ),
52 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
53 }
54 } else {
55 ((prefix.len() + suffix.len()).try_into().unwrap(), false)
56 };
57
58 for (idx, subpattern) in prefix.iter().enumerate() {
59 let elem =
60 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
61 let place = place.clone_project(elem);
62 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
63 }
64
65 if let Some(subslice_pat) = opt_slice {
66 let suffix_len = suffix.len() as u64;
67 let subslice = place.clone_project(PlaceElem::Subslice {
68 from: prefix.len() as u64,
69 to: if exact_size { min_length - suffix_len } else { suffix_len },
70 from_end: !exact_size,
71 });
72 MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
73 }
74
75 for (idx, subpattern) in suffix.iter().rev().enumerate() {
76 let end_offset = (idx + 1) as u64;
77 let elem = ProjectionElem::ConstantIndex {
78 offset: if exact_size { min_length - end_offset } else { end_offset },
79 min_length,
80 from_end: !exact_size,
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 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).ty;
110 ty != pattern.ty && ty.has_opaque_types()
111 }
112 _ => true,
113 };
114 if may_need_cast {
115 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
116 }
117
118 let place = place_builder.try_to_place(cx);
120 let mut subpairs = Vec::new();
121 let test_case = match pattern.kind {
122 PatKind::Wild | PatKind::Error(_) => None,
123
124 PatKind::Or { ref pats } => Some(TestCase::Or {
125 pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
126 }),
127
128 PatKind::Range(ref range) => {
129 if range.is_full_range(cx.tcx) == Some(true) {
130 None
131 } else {
132 Some(TestCase::Range(Arc::clone(range)))
133 }
134 }
135
136 PatKind::Constant { value } => Some(TestCase::Constant { value }),
137
138 PatKind::AscribeUserType {
139 ascription: Ascription { ref annotation, variance },
140 ref subpattern,
141 ..
142 } => {
143 MatchPairTree::for_pattern(
144 place_builder,
145 subpattern,
146 cx,
147 &mut subpairs,
148 extra_data,
149 );
150
151 if let Some(source) = place {
153 let annotation = annotation.clone();
154 extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
155 }
156
157 None
158 }
159
160 PatKind::Binding { mode, var, ref subpattern, .. } => {
161 if let Some(subpattern) = subpattern.as_ref() {
182 MatchPairTree::for_pattern(
184 place_builder,
185 subpattern,
186 cx,
187 &mut subpairs,
188 extra_data,
189 );
190 }
191
192 if let Some(source) = place {
194 extra_data.bindings.push(super::Binding {
195 span: pattern.span,
196 source,
197 var_id: var,
198 binding_mode: mode,
199 });
200 }
201
202 None
203 }
204
205 PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
206 MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
207 None
208 }
209 PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
210 MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
211
212 if let Some(source) = place {
214 let span = pattern.span;
215 let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
216 let args = ty::InlineConstArgs::new(
217 cx.tcx,
218 ty::InlineConstArgsParts {
219 parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
220 ty: cx.infcx.next_ty_var(span),
221 },
222 )
223 .args;
224 let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new(
225 ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }),
226 ));
227 let annotation = ty::CanonicalUserTypeAnnotation {
228 inferred_ty: pattern.ty,
229 span,
230 user_ty: Box::new(user_ty),
231 };
232 let variance = ty::Contravariant;
233 extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
234 }
235
236 None
237 }
238
239 PatKind::Array { ref prefix, ref slice, ref suffix } => {
240 cx.prefix_slice_suffix(
241 &mut subpairs,
242 extra_data,
243 &place_builder,
244 prefix,
245 slice,
246 suffix,
247 );
248 None
249 }
250 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
251 cx.prefix_slice_suffix(
252 &mut subpairs,
253 extra_data,
254 &place_builder,
255 prefix,
256 slice,
257 suffix,
258 );
259
260 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
261 None
262 } else {
263 Some(TestCase::Slice {
264 len: prefix.len() + suffix.len(),
265 variable_length: slice.is_some(),
266 })
267 }
268 }
269
270 PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
271 let downcast_place = place_builder.downcast(adt_def, variant_index); cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
273
274 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
275 i == variant_index
276 || !v.inhabited_predicate(cx.tcx, adt_def).instantiate(cx.tcx, args).apply(
277 cx.tcx,
278 cx.infcx.typing_env(cx.param_env),
279 cx.def_id.into(),
280 )
281 }) && !adt_def.variant_list_has_applicable_non_exhaustive();
282 if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
283 }
284
285 PatKind::Leaf { ref subpatterns } => {
286 cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
287 None
288 }
289
290 PatKind::Deref { ref subpattern } => {
291 MatchPairTree::for_pattern(
292 place_builder.deref(),
293 subpattern,
294 cx,
295 &mut subpairs,
296 extra_data,
297 );
298 None
299 }
300
301 PatKind::DerefPattern { ref subpattern, mutability } => {
302 let temp = cx.temp(
305 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
306 pattern.span,
307 );
308 MatchPairTree::for_pattern(
309 PlaceBuilder::from(temp).deref(),
310 subpattern,
311 cx,
312 &mut subpairs,
313 extra_data,
314 );
315 Some(TestCase::Deref { temp, mutability })
316 }
317
318 PatKind::Never => Some(TestCase::Never),
319 };
320
321 if let Some(test_case) = test_case {
322 match_pairs.push(MatchPairTree {
324 place: place.expect("refutable patterns should always have a place to inspect"),
325 test_case,
326 subpairs,
327 pattern_ty: pattern.ty,
328 pattern_span: pattern.span,
329 })
330 } else {
331 match_pairs.extend(subpairs);
334 }
335 }
336}