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 match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
47 ty::Array(_, length) => (
48 length
49 .try_to_target_usize(tcx)
50 .expect("expected len of array pat to be definite"),
51 true,
52 ),
53 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
54 }
55 } else {
56 ((prefix.len() + suffix.len()).try_into().unwrap(), false)
57 };
58
59 for (idx, subpattern) in prefix.iter().enumerate() {
60 let elem =
61 ProjectionElem::ConstantIndex { offset: idx as u64, 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 suffix_len = suffix.len() as u64;
68 let subslice = place.clone_project(PlaceElem::Subslice {
69 from: prefix.len() as u64,
70 to: if exact_size { min_length - suffix_len } else { suffix_len },
71 from_end: !exact_size,
72 });
73 MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
74 }
75
76 for (idx, subpattern) in suffix.iter().rev().enumerate() {
77 let end_offset = (idx + 1) as u64;
78 let elem = ProjectionElem::ConstantIndex {
79 offset: if exact_size { min_length - end_offset } else { end_offset },
80 min_length,
81 from_end: !exact_size,
82 };
83 let place = place.clone_project(elem);
84 MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
85 }
86 }
87}
88
89impl<'tcx> MatchPairTree<'tcx> {
90 pub(super) fn for_pattern(
93 mut place_builder: PlaceBuilder<'tcx>,
94 pattern: &Pat<'tcx>,
95 cx: &mut Builder<'_, 'tcx>,
96 match_pairs: &mut Vec<Self>, extra_data: &mut PatternExtraData<'tcx>, ) {
99 if let Some(resolved) = place_builder.resolve_upvar(cx) {
102 place_builder = resolved;
103 }
104
105 if !cx.tcx.next_trait_solver_globally() {
106 let may_need_cast = match place_builder.base() {
109 PlaceBase::Local(local) => {
110 let ty =
111 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
112 .ty;
113 ty != pattern.ty && ty.has_opaque_types()
114 }
115 _ => true,
116 };
117 if may_need_cast {
118 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
119 }
120 }
121
122 let place = place_builder.try_to_place(cx);
123 let mut subpairs = Vec::new();
124 let test_case = match pattern.kind {
125 PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
126
127 PatKind::Or { ref pats } => {
128 let pats: Box<[FlatPat<'tcx>]> =
129 pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
130 if !pats[0].extra_data.bindings.is_empty() {
131 extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
137 }
138 Some(TestCase::Or { pats })
139 }
140
141 PatKind::Range(ref range) => {
142 if range.is_full_range(cx.tcx) == Some(true) {
143 None
144 } else {
145 Some(TestCase::Range(Arc::clone(range)))
146 }
147 }
148
149 PatKind::Constant { value } => Some(TestCase::Constant { value }),
150
151 PatKind::AscribeUserType {
152 ascription: Ascription { ref annotation, variance },
153 ref subpattern,
154 ..
155 } => {
156 MatchPairTree::for_pattern(
157 place_builder,
158 subpattern,
159 cx,
160 &mut subpairs,
161 extra_data,
162 );
163
164 if let Some(source) = place {
166 let annotation = annotation.clone();
167 extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
168 }
169
170 None
171 }
172
173 PatKind::Binding { mode, var, ref subpattern, .. } => {
174 if let Some(subpattern) = subpattern.as_ref() {
195 MatchPairTree::for_pattern(
197 place_builder,
198 subpattern,
199 cx,
200 &mut subpairs,
201 extra_data,
202 );
203 }
204
205 if let Some(source) = place {
207 extra_data.bindings.push(super::SubpatternBindings::One(super::Binding {
208 span: pattern.span,
209 source,
210 var_id: var,
211 binding_mode: mode,
212 }));
213 }
214
215 None
216 }
217
218 PatKind::ExpandedConstant { subpattern: ref pattern, .. } => {
219 MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
220 None
221 }
222
223 PatKind::Array { ref prefix, ref slice, ref suffix } => {
224 cx.prefix_slice_suffix(
225 &mut subpairs,
226 extra_data,
227 &place_builder,
228 prefix,
229 slice,
230 suffix,
231 );
232 None
233 }
234 PatKind::Slice { 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
244 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
245 None
246 } else {
247 Some(TestCase::Slice {
248 len: prefix.len() + suffix.len(),
249 variable_length: slice.is_some(),
250 })
251 }
252 }
253
254 PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
255 let downcast_place = place_builder.downcast(adt_def, variant_index); cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
257
258 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
259 i == variant_index
260 || !v.inhabited_predicate(cx.tcx, adt_def).instantiate(cx.tcx, args).apply(
261 cx.tcx,
262 cx.infcx.typing_env(cx.param_env),
263 cx.def_id.into(),
264 )
265 }) && !adt_def.variant_list_has_applicable_non_exhaustive();
266 if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
267 }
268
269 PatKind::Leaf { ref subpatterns } => {
270 cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
271 None
272 }
273
274 PatKind::Deref { ref subpattern }
275 | PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
276 if cfg!(debug_assertions) && matches!(pattern.kind, PatKind::DerefPattern { .. }) {
277 debug_assert!(pattern.ty.is_box());
279 }
280
281 MatchPairTree::for_pattern(
282 place_builder.deref(),
283 subpattern,
284 cx,
285 &mut subpairs,
286 extra_data,
287 );
288 None
289 }
290
291 PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(mutability) } => {
292 let temp = cx.temp(
295 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
296 pattern.span,
297 );
298 MatchPairTree::for_pattern(
299 PlaceBuilder::from(temp).deref(),
300 subpattern,
301 cx,
302 &mut subpairs,
303 extra_data,
304 );
305 Some(TestCase::Deref { temp, mutability })
306 }
307
308 PatKind::Never => Some(TestCase::Never),
309 };
310
311 if let Some(test_case) = test_case {
312 match_pairs.push(MatchPairTree {
314 place,
315 test_case,
316 subpairs,
317 pattern_ty: pattern.ty,
318 pattern_span: pattern.span,
319 })
320 } else {
321 match_pairs.extend(subpairs);
324 }
325 }
326}