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