rustc_mir_build/builder/matches/
match_pair.rs
1use std::sync::Arc;
2
3use rustc_middle::mir::*;
4use rustc_middle::thir::{self, *};
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, TestCase};
10
11impl<'a, 'tcx> Builder<'a, 'tcx> {
12 fn field_match_pairs(
18 &mut self,
19 place: PlaceBuilder<'tcx>,
20 subpatterns: &[FieldPat<'tcx>],
21 ) -> Vec<MatchPairTree<'tcx>> {
22 subpatterns
23 .iter()
24 .map(|fieldpat| {
25 let place =
26 place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
27 MatchPairTree::for_pattern(place, &fieldpat.pattern, self)
28 })
29 .collect()
30 }
31
32 fn prefix_slice_suffix(
37 &mut self,
38 match_pairs: &mut Vec<MatchPairTree<'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 match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
60 let elem =
61 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
62 MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self)
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 match_pairs.push(MatchPairTree::for_pattern(subslice, subslice_pat, self));
73 }
74
75 match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
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)
84 }));
85 }
86}
87
88impl<'tcx> MatchPairTree<'tcx> {
89 pub(in crate::builder) fn for_pattern(
92 mut place_builder: PlaceBuilder<'tcx>,
93 pattern: &Pat<'tcx>,
94 cx: &mut Builder<'_, 'tcx>,
95 ) -> MatchPairTree<'tcx> {
96 if let Some(resolved) = place_builder.resolve_upvar(cx) {
99 place_builder = resolved;
100 }
101
102 let may_need_cast = match place_builder.base() {
105 PlaceBase::Local(local) => {
106 let ty =
107 Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
108 ty != pattern.ty && ty.has_opaque_types()
109 }
110 _ => true,
111 };
112 if may_need_cast {
113 place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
114 }
115
116 let place = place_builder.try_to_place(cx);
117 let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
118 let mut subpairs = Vec::new();
119 let test_case = match pattern.kind {
120 PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
121
122 PatKind::Or { ref pats } => TestCase::Or {
123 pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
124 },
125
126 PatKind::Range(ref range) => {
127 if range.is_full_range(cx.tcx) == Some(true) {
128 default_irrefutable()
129 } else {
130 TestCase::Range(Arc::clone(range))
131 }
132 }
133
134 PatKind::Constant { value } => TestCase::Constant { value },
135
136 PatKind::AscribeUserType {
137 ascription: thir::Ascription { ref annotation, variance },
138 ref subpattern,
139 ..
140 } => {
141 let ascription = place.map(|source| super::Ascription {
143 annotation: annotation.clone(),
144 source,
145 variance,
146 });
147
148 subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx));
149 TestCase::Irrefutable { ascription, binding: None }
150 }
151
152 PatKind::Binding { mode, var, ref subpattern, .. } => {
153 let binding = place.map(|source| super::Binding {
154 span: pattern.span,
155 source,
156 var_id: var,
157 binding_mode: mode,
158 });
159
160 if let Some(subpattern) = subpattern.as_ref() {
161 subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx));
163 }
164 TestCase::Irrefutable { ascription: None, binding }
165 }
166
167 PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
168 subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
169 default_irrefutable()
170 }
171 PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
172 let ascription = place.map(|source| {
174 let span = pattern.span;
175 let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
176 let args = ty::InlineConstArgs::new(
177 cx.tcx,
178 ty::InlineConstArgsParts {
179 parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
180 ty: cx.infcx.next_ty_var(span),
181 },
182 )
183 .args;
184 let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new(
185 ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }),
186 ));
187 let annotation = ty::CanonicalUserTypeAnnotation {
188 inferred_ty: pattern.ty,
189 span,
190 user_ty: Box::new(user_ty),
191 };
192 super::Ascription { annotation, source, variance: ty::Contravariant }
193 });
194
195 subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
196 TestCase::Irrefutable { ascription, binding: None }
197 }
198
199 PatKind::Array { ref prefix, ref slice, ref suffix } => {
200 cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
201 default_irrefutable()
202 }
203 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
204 cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
205
206 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
207 default_irrefutable()
208 } else {
209 TestCase::Slice {
210 len: prefix.len() + suffix.len(),
211 variable_length: slice.is_some(),
212 }
213 }
214 }
215
216 PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
217 let downcast_place = place_builder.downcast(adt_def, variant_index); subpairs = cx.field_match_pairs(downcast_place, subpatterns);
219
220 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
221 i == variant_index
222 || !v
223 .inhabited_predicate(cx.tcx, adt_def)
224 .instantiate(cx.tcx, args)
225 .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env))
226 }) && (adt_def.did().is_local()
227 || !adt_def.is_variant_list_non_exhaustive());
228 if irrefutable {
229 default_irrefutable()
230 } else {
231 TestCase::Variant { adt_def, variant_index }
232 }
233 }
234
235 PatKind::Leaf { ref subpatterns } => {
236 subpairs = cx.field_match_pairs(place_builder, subpatterns);
237 default_irrefutable()
238 }
239
240 PatKind::Deref { ref subpattern } => {
241 subpairs.push(MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx));
242 default_irrefutable()
243 }
244
245 PatKind::DerefPattern { ref subpattern, mutability } => {
246 let temp = cx.temp(
249 Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
250 pattern.span,
251 );
252 subpairs.push(MatchPairTree::for_pattern(
253 PlaceBuilder::from(temp).deref(),
254 subpattern,
255 cx,
256 ));
257 TestCase::Deref { temp, mutability }
258 }
259
260 PatKind::Never => TestCase::Never,
261 };
262
263 MatchPairTree {
264 place,
265 test_case,
266 subpairs,
267 pattern_ty: pattern.ty,
268 pattern_span: pattern.span,
269 }
270 }
271}