1 use crate::build::expr::as_place::PlaceBase; 2 use crate::build::expr::as_place::PlaceBuilder; 3 use crate::build::matches::MatchPair; 4 use crate::build::Builder; 5 use rustc_middle::mir::*; 6 use rustc_middle::thir::*; 7 use rustc_middle::ty; 8 use rustc_middle::ty::TypeVisitableExt; 9 use smallvec::SmallVec; 10 11 impl<'a, 'tcx> Builder<'a, 'tcx> { field_match_pairs<'pat>( &mut self, place: PlaceBuilder<'tcx>, subpatterns: &'pat [FieldPat<'tcx>], ) -> Vec<MatchPair<'pat, 'tcx>>12 pub(crate) fn field_match_pairs<'pat>( 13 &mut self, 14 place: PlaceBuilder<'tcx>, 15 subpatterns: &'pat [FieldPat<'tcx>], 16 ) -> Vec<MatchPair<'pat, 'tcx>> { 17 subpatterns 18 .iter() 19 .map(|fieldpat| { 20 let place = 21 place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); 22 MatchPair::new(place, &fieldpat.pattern, self) 23 }) 24 .collect() 25 } 26 prefix_slice_suffix<'pat>( &mut self, match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, place: &PlaceBuilder<'tcx>, prefix: &'pat [Box<Pat<'tcx>>], opt_slice: &'pat Option<Box<Pat<'tcx>>>, suffix: &'pat [Box<Pat<'tcx>>], )27 pub(crate) fn prefix_slice_suffix<'pat>( 28 &mut self, 29 match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, 30 place: &PlaceBuilder<'tcx>, 31 prefix: &'pat [Box<Pat<'tcx>>], 32 opt_slice: &'pat Option<Box<Pat<'tcx>>>, 33 suffix: &'pat [Box<Pat<'tcx>>], 34 ) { 35 let tcx = self.tcx; 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() { 38 ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), 39 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), 40 } 41 } else { 42 ((prefix.len() + suffix.len()).try_into().unwrap(), false) 43 }; 44 45 match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { 46 let elem = 47 ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; 48 MatchPair::new(place.clone_project(elem), subpattern, self) 49 })); 50 51 if let Some(subslice_pat) = opt_slice { 52 let suffix_len = suffix.len() as u64; 53 let subslice = place.clone_project(PlaceElem::Subslice { 54 from: prefix.len() as u64, 55 to: if exact_size { min_length - suffix_len } else { suffix_len }, 56 from_end: !exact_size, 57 }); 58 match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); 59 } 60 61 match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { 62 let end_offset = (idx + 1) as u64; 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 }; 68 let place = place.clone_project(elem); 69 MatchPair::new(place, subpattern, self) 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. false_edges( &mut self, from_block: BasicBlock, real_target: BasicBlock, imaginary_target: Option<BasicBlock>, source_info: SourceInfo, )76 pub(crate) fn false_edges( 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, 88 TerminatorKind::FalseEdge { real_target, imaginary_target: target }, 89 ); 90 } 91 _ => self.cfg.goto(from_block, source_info, real_target), 92 } 93 } 94 } 95 96 impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { new( mut place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, cx: &Builder<'_, 'tcx>, ) -> MatchPair<'pat, 'tcx>97 pub(in crate::build) fn new( 98 mut place: PlaceBuilder<'tcx>, 99 pattern: &'pat Pat<'tcx>, 100 cx: &Builder<'_, 'tcx>, 101 ) -> MatchPair<'pat, 'tcx> { 102 // Force the place type to the pattern's type. 103 // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? 104 if let Some(resolved) = place.resolve_upvar(cx) { 105 place = resolved; 106 } 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 } 120 MatchPair { place, pattern } 121 } 122 } 123