• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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