rustc_mir_build/builder/matches/
match_pair.rs1use std::sync::Arc;
2
3use rustc_hir::ByRef;
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::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
11
12impl<'a, 'tcx> Builder<'a, 'tcx> {
13 fn field_match_pairs(
19 &mut self,
20 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
21 extra_data: &mut PatternExtraData<'tcx>,
22 place: PlaceBuilder<'tcx>,
23 subpatterns: &[FieldPat<'tcx>],
24 ) {
25 for fieldpat in subpatterns {
26 let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
27 MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
28 }
29 }
30
31 fn prefix_slice_suffix(
36 &mut self,
37 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
38 extra_data: &mut PatternExtraData<'tcx>,
39 place: &PlaceBuilder<'tcx>,
40 prefix: &[Pat<'tcx>],
41 opt_slice: &Option<Box<Pat<'tcx>>>,
42 suffix: &[Pat<'tcx>],
43 ) {
44 let tcx = self.tcx;
45 let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
46 let place_ty = place_resolved.ty(&self.local_decls, tcx).ty;
47 match place_ty.kind() {
48 ty::Array(_, length) => {
49 if let Some(length) = length.try_to_target_usize(tcx) {
50 (length, true)
51 } else {
52 tcx.dcx().span_delayed_bug(
57 tcx.def_span(self.def_id),
58 "array length in pattern couldn't be evaluated",
59 );
60 ((prefix.len() + suffix.len()).try_into().unwrap(), false)
61 }
62 }
63 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
64 }
65 } else {
66 ((prefix.len() + suffix.len()).try_into().unwrap(), false)
67 };
68
69 for (idx, subpattern) in prefix.iter().enumerate() {
70 let elem =
71 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
72 let place = place.clone_project(elem);
73 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
74 }
75
76 if let Some(subslice_pat) = opt_slice {
77 let suffix_len = suffix.len() as u64;
78 let subslice = place.clone_project(PlaceElem::Subslice {
79 from: prefix.len() as u64,
80 to: if exact_size { min_length - suffix_len } else { suffix_len },
81 from_end: !exact_size,
82 });
83 MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
84 }
85
86 for (idx, subpattern) in suffix.iter().rev().enumerate() {
87 let end_offset = (idx + 1) as u64;
88 let elem = ProjectionElem::ConstantIndex {
89 offset: if exact_size { min_length - end_offset } else { end_offset },
90 min_length,
91 from_end: !exact_size,
92 };
93 let place = place.clone_project(elem);
94 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
95 }
96 }
97}
98
99impl<'tcx> MatchPairTree<'tcx> {
100 pub(super) fn for_pattern(
103 mut place_builder: PlaceBuilder<'tcx>,
104 pattern: &Pat<'tcx>,
105 cx: &mut Builder<'_, 'tcx>,
106 match_pairs: &mut Vec<Self>, extra_data: &mut PatternExtraData<'tcx>, ) {
109 if let Some(resolved) = place_builder.resolve_upvar(cx) {
112 place_builder = resolved;
113 }
114
115 if !cx.tcx.next_trait_solver_globally() {
116 let may_need_cast = match place_builder.base() {
119 PlaceBase::Local(local) => {
120 let ty =
121 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
122 .ty;
123 ty != pattern.ty && ty.has_opaque_types()
124 }
125 _ => true,
126 };
127 if may_need_cast {
128 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
129 }
130 }
131
132 let place = place_builder.try_to_place(cx);
133 let mut subpairs = Vec::new();
134 let test_case = match pattern.kind {
135 PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
136
137 PatKind::Or { ref pats } => {
138 let pats: Box<[FlatPat<'tcx>]> =
139 pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
140 if !pats[0].extra_data.bindings.is_empty() {
141 extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
147 }
148 Some(TestCase::Or { pats })
149 }
150
151 PatKind::Range(ref range) => {
152 if range.is_full_range(cx.tcx) == Some(true) {
153 None
154 } else {
155 Some(TestCase::Range(Arc::clone(range)))
156 }
157 }
158
159 PatKind::Constant { value } => Some(TestCase::Constant { value }),
160
161 PatKind::AscribeUserType {
162 ascription: Ascription { ref annotation, variance },
163 ref subpattern,
164 ..
165 } => {
166 MatchPairTree::for_pattern(
167 place_builder,
168 subpattern,
169 cx,
170 &mut subpairs,
171 extra_data,
172 );
173
174 if let Some(source) = place {
176 let annotation = annotation.clone();
177 extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
178 }
179
180 None
181 }
182
183 PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => {
184 if let Some(subpattern) = subpattern.as_ref() {
205 MatchPairTree::for_pattern(
207 place_builder,
208 subpattern,
209 cx,
210 &mut subpairs,
211 extra_data,
212 );
213 }
214
215 if let Some(source) = place {
217 extra_data.bindings.push(super::SubpatternBindings::One(super::Binding {
218 span: pattern.span,
219 source,
220 var_id: var,
221 binding_mode: mode,
222 is_shorthand,
223 }));
224 }
225
226 None
227 }
228
229 PatKind::ExpandedConstant { subpattern: ref pattern, .. } => {
230 MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
231 None
232 }
233
234 PatKind::Array { ref prefix, ref slice, ref suffix } => {
235 cx.prefix_slice_suffix(
236 &mut subpairs,
237 extra_data,
238 &place_builder,
239 prefix,
240 slice,
241 suffix,
242 );
243 None
244 }
245 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
246 cx.prefix_slice_suffix(
247 &mut subpairs,
248 extra_data,
249 &place_builder,
250 prefix,
251 slice,
252 suffix,
253 );
254
255 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
256 None
257 } else {
258 Some(TestCase::Slice {
259 len: prefix.len() + suffix.len(),
260 variable_length: slice.is_some(),
261 })
262 }
263 }
264
265 PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
266 let downcast_place = place_builder.downcast(adt_def, variant_index); cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
268
269 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
270 i == variant_index
271 || !v.inhabited_predicate(cx.tcx, adt_def).instantiate(cx.tcx, args).apply(
272 cx.tcx,
273 cx.infcx.typing_env(cx.param_env),
274 cx.def_id.into(),
275 )
276 }) && !adt_def.variant_list_has_applicable_non_exhaustive();
277 if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
278 }
279
280 PatKind::Leaf { ref subpatterns } => {
281 cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
282 None
283 }
284
285 PatKind::Deref { ref subpattern }
286 | PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
287 if cfg!(debug_assertions) && matches!(pattern.kind, PatKind::DerefPattern { .. }) {
288 debug_assert!(pattern.ty.is_box());
290 }
291
292 MatchPairTree::for_pattern(
293 place_builder.deref(),
294 subpattern,
295 cx,
296 &mut subpairs,
297 extra_data,
298 );
299 None
300 }
301
302 PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(mutability) } => {
303 let temp = cx.temp(
306 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
307 pattern.span,
308 );
309 MatchPairTree::for_pattern(
310 PlaceBuilder::from(temp).deref(),
311 subpattern,
312 cx,
313 &mut subpairs,
314 extra_data,
315 );
316 Some(TestCase::Deref { temp, mutability })
317 }
318
319 PatKind::Never => Some(TestCase::Never),
320 };
321
322 if let Some(test_case) = test_case {
323 match_pairs.push(MatchPairTree {
325 place,
326 test_case,
327 subpairs,
328 pattern_ty: pattern.ty,
329 pattern_span: pattern.span,
330 })
331 } else {
332 match_pairs.extend(subpairs);
335 }
336 }
337}