|
| 1 | +use either::Either; |
1 | 2 | use rustc_middle::mir::*; |
2 | 3 | use rustc_middle::thir::{self, *}; |
3 | 4 | use rustc_middle::ty::{self, Ty, TypeVisitableExt}; |
@@ -117,6 +118,81 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
117 | 118 | } |
118 | 119 | } |
119 | 120 |
|
| 121 | + fn build_slice_branch<'pat>( |
| 122 | + &'pat mut self, |
| 123 | + place: &'pat PlaceBuilder<'tcx>, |
| 124 | + top_pattern: &'pat Pat<'tcx>, |
| 125 | + pattern: &'pat [Box<Pat<'tcx>>], |
| 126 | + ) -> impl Iterator<Item = MatchPairTree<'pat, 'tcx>> + use<'pat, 'tcx, 'a> { |
| 127 | + self.find_const_groups(pattern).into_iter().map(move |entry| { |
| 128 | + let pattern_len = pattern.len() as u64; |
| 129 | + let mut build_single = |idx| { |
| 130 | + let subpattern = &pattern[idx as usize]; |
| 131 | + let place = place.clone_project(ProjectionElem::ConstantIndex { |
| 132 | + offset: idx, |
| 133 | + min_length: pattern_len, |
| 134 | + from_end: false, |
| 135 | + }); |
| 136 | + |
| 137 | + MatchPairTree::for_pattern(place, subpattern, self) |
| 138 | + }; |
| 139 | + |
| 140 | + match entry { |
| 141 | + Either::Right(range) if range.len() > 1 => { |
| 142 | + assert!( |
| 143 | + (range.start..range.end) |
| 144 | + .all(|idx| self.is_constant_pattern(&pattern[idx as usize])) |
| 145 | + ); |
| 146 | + |
| 147 | + let subpattern = &pattern[range.start as usize..range.end as usize]; |
| 148 | + let elem_ty = subpattern[0].ty; |
| 149 | + |
| 150 | + let place = place.clone_project(PlaceElem::Subslice { |
| 151 | + from: range.start, |
| 152 | + to: pattern.len() as u64 - range.end, |
| 153 | + from_end: true, |
| 154 | + }); |
| 155 | + |
| 156 | + let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); |
| 157 | + self.valtree_to_match_pair(top_pattern, valtree, place, elem_ty, range, false) |
| 158 | + } |
| 159 | + Either::Right(range) => { |
| 160 | + let tree = build_single(range.start); |
| 161 | + assert!(self.is_constant_pattern(&pattern[range.start as usize])); |
| 162 | + tree |
| 163 | + } |
| 164 | + Either::Left(idx) => build_single(idx), |
| 165 | + } |
| 166 | + }) |
| 167 | + } |
| 168 | + |
| 169 | + fn find_const_groups(&self, pattern: &[Box<Pat<'tcx>>]) -> Vec<Either<u64, Range>> { |
| 170 | + let mut entries = Vec::new(); |
| 171 | + let mut current_seq_start = None; |
| 172 | + |
| 173 | + let mut apply = |state: &mut _, idx| { |
| 174 | + if let Some(start) = *state { |
| 175 | + *state = None; |
| 176 | + entries.push(Either::Right(Range::from_start(start..idx))); |
| 177 | + } else { |
| 178 | + entries.push(Either::Left(idx)); |
| 179 | + } |
| 180 | + }; |
| 181 | + |
| 182 | + for (idx, pat) in pattern.iter().enumerate() { |
| 183 | + if self.is_constant_pattern(pat) { |
| 184 | + if current_seq_start.is_none() { |
| 185 | + current_seq_start = Some(idx as u64); |
| 186 | + } |
| 187 | + } else { |
| 188 | + apply(&mut current_seq_start, idx as u64); |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + apply(&mut current_seq_start, pattern.len() as u64); |
| 193 | + entries |
| 194 | + } |
| 195 | + |
120 | 196 | fn should_optimize_subslice(&self, subslice: &[Box<Pat<'tcx>>]) -> bool { |
121 | 197 | subslice.len() > 1 && subslice.iter().all(|p| self.is_constant_pattern(p)) |
122 | 198 | } |
@@ -161,16 +237,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
161 | 237 | place: PlaceBuilder<'tcx>, |
162 | 238 | elem_ty: Ty<'tcx>, |
163 | 239 | range: Range, |
164 | | - subsliced: bool, |
| 240 | + do_own_slice: bool, |
165 | 241 | ) -> MatchPairTree<'pat, 'tcx> { |
166 | 242 | let tcx = self.tcx; |
167 | 243 | let const_ty = |
168 | 244 | Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, Ty::new_array(tcx, elem_ty, range.len())); |
169 | 245 |
|
170 | | - let pat_ty = if subsliced { Ty::new_slice(tcx, elem_ty) } else { source_pattern.ty }; |
| 246 | + let pat_ty = if do_own_slice { Ty::new_slice(tcx, elem_ty) } else { source_pattern.ty }; |
171 | 247 | let ty_const = ty::Const::new(tcx, ty::ConstKind::Value(const_ty, valtree)); |
172 | 248 | let value = Const::Ty(const_ty, ty_const); |
173 | | - let test_case = TestCase::Constant { value, range: subsliced.then_some(range) }; |
| 249 | + let test_case = TestCase::Constant { value, range: do_own_slice.then_some(range) }; |
174 | 250 | let pattern = tcx.arena.alloc(Pat { |
175 | 251 | ty: pat_ty, |
176 | 252 | span: source_pattern.span, |
|
0 commit comments