]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | use crate::build::expr::as_place::PlaceBase; |
6a06907d | 2 | use crate::build::expr::as_place::PlaceBuilder; |
dfeec247 XL |
3 | use crate::build::matches::MatchPair; |
4 | use crate::build::Builder; | |
ba9703b0 | 5 | use rustc_middle::mir::*; |
17df50a5 | 6 | use rustc_middle::thir::*; |
ba9703b0 | 7 | use rustc_middle::ty; |
9ffffee4 | 8 | use rustc_middle::ty::TypeVisitableExt; |
dfeec247 | 9 | use smallvec::SmallVec; |
dfeec247 XL |
10 | |
11 | impl<'a, 'tcx> Builder<'a, 'tcx> { | |
923072b8 | 12 | pub(crate) fn field_match_pairs<'pat>( |
dfeec247 | 13 | &mut self, |
6a06907d | 14 | place: PlaceBuilder<'tcx>, |
dfeec247 XL |
15 | subpatterns: &'pat [FieldPat<'tcx>], |
16 | ) -> Vec<MatchPair<'pat, 'tcx>> { | |
17 | subpatterns | |
18 | .iter() | |
19 | .map(|fieldpat| { | |
487cf647 FG |
20 | let place = |
21 | place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); | |
2b03887a | 22 | MatchPair::new(place, &fieldpat.pattern, self) |
dfeec247 XL |
23 | }) |
24 | .collect() | |
25 | } | |
26 | ||
923072b8 | 27 | pub(crate) fn prefix_slice_suffix<'pat>( |
dfeec247 XL |
28 | &mut self, |
29 | match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, | |
6a06907d | 30 | place: &PlaceBuilder<'tcx>, |
f2b60f7d FG |
31 | prefix: &'pat [Box<Pat<'tcx>>], |
32 | opt_slice: &'pat Option<Box<Pat<'tcx>>>, | |
33 | suffix: &'pat [Box<Pat<'tcx>>], | |
dfeec247 | 34 | ) { |
6a06907d | 35 | let tcx = self.tcx; |
487cf647 FG |
36 | let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { |
37 | match place_resolved.ty(&self.local_decls, tcx).ty.kind() { | |
9ffffee4 | 38 | ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), |
487cf647 FG |
39 | _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), |
40 | } | |
41 | } else { | |
42 | ((prefix.len() + suffix.len()).try_into().unwrap(), false) | |
43 | }; | |
dfeec247 XL |
44 | |
45 | match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { | |
46 | let elem = | |
1b1a35ee | 47 | ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; |
487cf647 | 48 | MatchPair::new(place.clone_project(elem), subpattern, self) |
dfeec247 XL |
49 | })); |
50 | ||
51 | if let Some(subslice_pat) = opt_slice { | |
1b1a35ee | 52 | let suffix_len = suffix.len() as u64; |
487cf647 | 53 | let subslice = place.clone_project(PlaceElem::Subslice { |
6a06907d XL |
54 | from: prefix.len() as u64, |
55 | to: if exact_size { min_length - suffix_len } else { suffix_len }, | |
56 | from_end: !exact_size, | |
57 | }); | |
2b03887a | 58 | match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); |
dfeec247 XL |
59 | } |
60 | ||
61 | match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { | |
1b1a35ee | 62 | let end_offset = (idx + 1) as u64; |
dfeec247 XL |
63 | let elem = ProjectionElem::ConstantIndex { |
64 | offset: if exact_size { min_length - end_offset } else { end_offset }, | |
65 | min_length, | |
66 | from_end: !exact_size, | |
67 | }; | |
487cf647 | 68 | let place = place.clone_project(elem); |
2b03887a | 69 | MatchPair::new(place, subpattern, self) |
dfeec247 XL |
70 | })); |
71 | } | |
72 | ||
73 | /// Creates a false edge to `imaginary_target` and a real edge to | |
74 | /// real_target. If `imaginary_target` is none, or is the same as the real | |
75 | /// target, a Goto is generated instead to simplify the generated MIR. | |
923072b8 | 76 | pub(crate) fn false_edges( |
dfeec247 XL |
77 | &mut self, |
78 | from_block: BasicBlock, | |
79 | real_target: BasicBlock, | |
80 | imaginary_target: Option<BasicBlock>, | |
81 | source_info: SourceInfo, | |
82 | ) { | |
83 | match imaginary_target { | |
84 | Some(target) if target != real_target => { | |
85 | self.cfg.terminate( | |
86 | from_block, | |
87 | source_info, | |
f035d41b | 88 | TerminatorKind::FalseEdge { real_target, imaginary_target: target }, |
dfeec247 XL |
89 | ); |
90 | } | |
91 | _ => self.cfg.goto(from_block, source_info, real_target), | |
92 | } | |
93 | } | |
94 | } | |
95 | ||
96 | impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { | |
2b03887a | 97 | pub(in crate::build) fn new( |
487cf647 | 98 | mut place: PlaceBuilder<'tcx>, |
923072b8 | 99 | pattern: &'pat Pat<'tcx>, |
2b03887a | 100 | cx: &Builder<'_, 'tcx>, |
923072b8 | 101 | ) -> MatchPair<'pat, 'tcx> { |
2b03887a FG |
102 | // Force the place type to the pattern's type. |
103 | // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? | |
487cf647 FG |
104 | if let Some(resolved) = place.resolve_upvar(cx) { |
105 | place = resolved; | |
106 | } | |
2b03887a FG |
107 | |
108 | // Only add the OpaqueCast projection if the given place is an opaque type and the | |
109 | // expected type from the pattern is not. | |
110 | let may_need_cast = match place.base() { | |
111 | PlaceBase::Local(local) => { | |
112 | let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty; | |
113 | ty != pattern.ty && ty.has_opaque_types() | |
114 | } | |
115 | _ => true, | |
116 | }; | |
117 | if may_need_cast { | |
118 | place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); | |
119 | } | |
dfeec247 XL |
120 | MatchPair { place, pattern } |
121 | } | |
122 | } |