1 //! Locals are in a private module as updating `LocalRef::Operand` has to 2 //! be careful wrt to subtyping. To deal with this we only allow updates by using 3 //! `FunctionCx::overwrite_local` which handles it automatically. 4 use crate::mir::{FunctionCx, LocalRef}; 5 use crate::traits::BuilderMethods; 6 use rustc_index::IndexVec; 7 use rustc_middle::mir; 8 use rustc_middle::ty::print::with_no_trimmed_paths; 9 use std::ops::{Index, IndexMut}; 10 11 pub(super) struct Locals<'tcx, V> { 12 values: IndexVec<mir::Local, LocalRef<'tcx, V>>, 13 } 14 15 impl<'tcx, V> Index<mir::Local> for Locals<'tcx, V> { 16 type Output = LocalRef<'tcx, V>; 17 #[inline] index(&self, index: mir::Local) -> &LocalRef<'tcx, V>18 fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> { 19 &self.values[index] 20 } 21 } 22 23 /// To mutate locals, use `FunctionCx::overwrite_local` instead. 24 impl<'tcx, V, Idx: ?Sized> !IndexMut<Idx> for Locals<'tcx, V> {} 25 26 impl<'tcx, V> Locals<'tcx, V> { empty() -> Locals<'tcx, V>27 pub(super) fn empty() -> Locals<'tcx, V> { 28 Locals { values: IndexVec::default() } 29 } 30 indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx31 pub(super) fn indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx { 32 self.values.indices() 33 } 34 } 35 36 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>)37 pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) { 38 assert!(self.locals.values.is_empty()); 39 40 for (local, value) in values.into_iter().enumerate() { 41 match value { 42 LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (), 43 LocalRef::Operand(op) => { 44 let local = mir::Local::from_usize(local); 45 let expected_ty = self.monomorphize(self.mir.local_decls[local].ty); 46 assert_eq!(expected_ty, op.layout.ty, "unexpected initial operand type"); 47 } 48 } 49 50 self.locals.values.push(value); 51 } 52 } 53 overwrite_local( &mut self, local: mir::Local, mut value: LocalRef<'tcx, Bx::Value>, )54 pub(super) fn overwrite_local( 55 &mut self, 56 local: mir::Local, 57 mut value: LocalRef<'tcx, Bx::Value>, 58 ) { 59 match value { 60 LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (), 61 LocalRef::Operand(ref mut op) => { 62 let local_ty = self.monomorphize(self.mir.local_decls[local].ty); 63 if local_ty != op.layout.ty { 64 // FIXME(#112651): This can be changed to an ICE afterwards. 65 debug!("updating type of operand due to subtyping"); 66 with_no_trimmed_paths!(debug!(?op.layout.ty)); 67 with_no_trimmed_paths!(debug!(?local_ty)); 68 op.layout.ty = local_ty; 69 } 70 } 71 }; 72 73 self.locals.values[local] = value; 74 } 75 } 76