]>
Commit | Line | Data |
---|---|---|
92a42be0 SL |
1 | /*! |
2 | * Methods for the various MIR types. These are intended for use after | |
3 | * building is complete. | |
4 | */ | |
5 | ||
9fa01778 | 6 | use crate::mir::*; |
dfeec247 XL |
7 | use crate::ty::{self, Ty, TyCtxt}; |
8 | use rustc_hir as hir; | |
ba9703b0 | 9 | use rustc_target::abi::VariantIdx; |
92a42be0 | 10 | |
064997fb | 11 | #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] |
532ac7d7 XL |
12 | pub struct PlaceTy<'tcx> { |
13 | pub ty: Ty<'tcx>, | |
04454e1e | 14 | /// Downcast to a particular variant of an enum or a generator, if included. |
532ac7d7 | 15 | pub variant_index: Option<VariantIdx>, |
92a42be0 SL |
16 | } |
17 | ||
48663c56 | 18 | // At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. |
6a06907d | 19 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
48663c56 | 20 | static_assert_size!(PlaceTy<'_>, 16); |
a1dfa0c6 | 21 | |
dc9dc135 | 22 | impl<'tcx> PlaceTy<'tcx> { |
6a06907d | 23 | #[inline] |
ff7c6d11 | 24 | pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { |
532ac7d7 | 25 | PlaceTy { ty, variant_index: None } |
92a42be0 SL |
26 | } |
27 | ||
0bf4aa26 XL |
28 | /// `place_ty.field_ty(tcx, f)` computes the type at a given field |
29 | /// of a record or enum-variant. (Most clients of `PlaceTy` can | |
30 | /// instead just extract the relevant type directly from their | |
31 | /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do | |
32 | /// not carry a `Ty` for `T`.) | |
33 | /// | |
34 | /// Note that the resulting type has not been normalized. | |
9c376795 | 35 | #[instrument(level = "debug", skip(tcx), ret)] |
5e7ed085 | 36 | pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> { |
9c376795 | 37 | match self.ty.kind() { |
532ac7d7 XL |
38 | ty::Adt(adt_def, substs) => { |
39 | let variant_def = match self.variant_index { | |
40 | None => adt_def.non_enum_variant(), | |
41 | Some(variant_index) => { | |
42 | assert!(adt_def.is_enum()); | |
5e7ed085 | 43 | &adt_def.variant(variant_index) |
532ac7d7 XL |
44 | } |
45 | }; | |
0bf4aa26 XL |
46 | let field_def = &variant_def.fields[f.index()]; |
47 | field_def.ty(tcx, substs) | |
48 | } | |
5e7ed085 | 49 | ty::Tuple(tys) => tys[f.index()], |
532ac7d7 | 50 | _ => bug!("extracting field of non-tuple non-adt: {:?}", self), |
9c376795 | 51 | } |
0bf4aa26 XL |
52 | } |
53 | ||
54 | /// Convenience wrapper around `projection_ty_core` for | |
55 | /// `PlaceElem`, where we can just use the `Ty` that is already | |
56 | /// stored inline on field projection elems. | |
f9f354fc | 57 | pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { |
2b03887a | 58 | self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty) |
0bf4aa26 XL |
59 | } |
60 | ||
61 | /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` | |
62 | /// projects `place_ty` onto `elem`, returning the appropriate | |
63 | /// `Ty` or downcast variant corresponding to that projection. | |
64 | /// The `handle_field` callback must map a `Field` to its `Ty`, | |
65 | /// (which should be trivial when `T` = `Ty`). | |
9fa01778 | 66 | pub fn projection_ty_core<V, T>( |
13cf67c4 | 67 | self, |
dc9dc135 | 68 | tcx: TyCtxt<'tcx>, |
416331ca | 69 | param_env: ty::ParamEnv<'tcx>, |
532ac7d7 | 70 | elem: &ProjectionElem<V, T>, |
5e7ed085 | 71 | mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, |
2b03887a | 72 | mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, |
dc9dc135 | 73 | ) -> PlaceTy<'tcx> |
0bf4aa26 | 74 | where |
dc9dc135 | 75 | V: ::std::fmt::Debug, |
5e7ed085 | 76 | T: ::std::fmt::Debug + Copy, |
0bf4aa26 | 77 | { |
04454e1e FG |
78 | if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) { |
79 | bug!("cannot use non field projection on downcasted place") | |
80 | } | |
0bf4aa26 | 81 | let answer = match *elem { |
c30ab7b3 | 82 | ProjectionElem::Deref => { |
dfeec247 XL |
83 | let ty = self |
84 | .ty | |
85 | .builtin_deref(true) | |
86 | .unwrap_or_else(|| { | |
87 | bug!("deref projection of non-dereferenceable ty {:?}", self) | |
88 | }) | |
89 | .ty; | |
532ac7d7 | 90 | PlaceTy::from_ty(ty) |
c30ab7b3 | 91 | } |
dfeec247 XL |
92 | ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { |
93 | PlaceTy::from_ty(self.ty.builtin_index().unwrap()) | |
94 | } | |
60c5eb7d | 95 | ProjectionElem::Subslice { from, to, from_end } => { |
1b1a35ee | 96 | PlaceTy::from_ty(match self.ty.kind() { |
60c5eb7d | 97 | ty::Slice(..) => self.ty, |
5099ac24 | 98 | ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), |
60c5eb7d | 99 | ty::Array(inner, size) if from_end => { |
416331ca | 100 | let size = size.eval_usize(tcx, param_env); |
532ac7d7 | 101 | let len = size - (from as u64) - (to as u64); |
5099ac24 | 102 | tcx.mk_array(*inner, len) |
92a42be0 | 103 | } |
dfeec247 | 104 | _ => bug!("cannot subslice non-array type: `{:?}`", self), |
532ac7d7 XL |
105 | }) |
106 | } | |
dfeec247 XL |
107 | ProjectionElem::Downcast(_name, index) => { |
108 | PlaceTy { ty: self.ty, variant_index: Some(index) } | |
109 | } | |
5e7ed085 | 110 | ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), |
2b03887a | 111 | ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)), |
0bf4aa26 XL |
112 | }; |
113 | debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); | |
9fa01778 | 114 | answer |
92a42be0 SL |
115 | } |
116 | } | |
117 | ||
ff7c6d11 | 118 | impl<'tcx> Place<'tcx> { |
416331ca | 119 | pub fn ty_from<D>( |
74b04a01 | 120 | local: Local, |
e1599b0c | 121 | projection: &[PlaceElem<'tcx>], |
416331ca | 122 | local_decls: &D, |
dfeec247 | 123 | tcx: TyCtxt<'tcx>, |
416331ca | 124 | ) -> PlaceTy<'tcx> |
dfeec247 XL |
125 | where |
126 | D: HasLocalDecls<'tcx>, | |
dc9dc135 | 127 | { |
dfeec247 XL |
128 | projection |
129 | .iter() | |
f9f354fc | 130 | .fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, &elem| { |
dfeec247 XL |
131 | place_ty.projection_ty(tcx, elem) |
132 | }) | |
dc9dc135 | 133 | } |
416331ca XL |
134 | |
135 | pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> | |
136 | where | |
fc512014 XL |
137 | D: HasLocalDecls<'tcx>, |
138 | { | |
139 | Place::ty_from(self.local, &self.projection, local_decls, tcx) | |
140 | } | |
141 | } | |
142 | ||
143 | impl<'tcx> PlaceRef<'tcx> { | |
144 | pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> | |
145 | where | |
416331ca XL |
146 | D: HasLocalDecls<'tcx>, |
147 | { | |
74b04a01 | 148 | Place::ty_from(self.local, &self.projection, local_decls, tcx) |
92a42be0 | 149 | } |
5bcae85e | 150 | } |
7453a54e | 151 | |
3b2f2976 XL |
152 | pub enum RvalueInitializationState { |
153 | Shallow, | |
dfeec247 | 154 | Deep, |
3b2f2976 XL |
155 | } |
156 | ||
5bcae85e | 157 | impl<'tcx> Rvalue<'tcx> { |
dc9dc135 XL |
158 | pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> |
159 | where | |
160 | D: HasLocalDecls<'tcx>, | |
7453a54e | 161 | { |
8bb4bdeb | 162 | match *self { |
041b39d2 | 163 | Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), |
ba9703b0 XL |
164 | Rvalue::Repeat(ref operand, count) => { |
165 | tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count)) | |
166 | } | |
f9f354fc | 167 | Rvalue::ThreadLocalRef(did) => { |
29967ef6 | 168 | let static_ty = tcx.type_of(did); |
f9f354fc | 169 | if tcx.is_mutable_static(did) { |
29967ef6 XL |
170 | tcx.mk_mut_ptr(static_ty) |
171 | } else if tcx.is_foreign_item(did) { | |
172 | tcx.mk_imm_ptr(static_ty) | |
f9f354fc | 173 | } else { |
29967ef6 XL |
174 | // FIXME: These things don't *really* have 'static lifetime. |
175 | tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty) | |
f9f354fc XL |
176 | } |
177 | } | |
ff7c6d11 | 178 | Rvalue::Ref(reg, bk, ref place) => { |
532ac7d7 | 179 | let place_ty = place.ty(local_decls, tcx).ty; |
dfeec247 XL |
180 | tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) |
181 | } | |
182 | Rvalue::AddressOf(mutability, ref place) => { | |
183 | let place_ty = place.ty(local_decls, tcx).ty; | |
74b04a01 | 184 | tcx.mk_ptr(ty::TypeAndMut { ty: place_ty, mutbl: mutability }) |
7453a54e | 185 | } |
8bb4bdeb XL |
186 | Rvalue::Len(..) => tcx.types.usize, |
187 | Rvalue::Cast(.., ty) => ty, | |
6a06907d | 188 | Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { |
041b39d2 XL |
189 | let lhs_ty = lhs.ty(local_decls, tcx); |
190 | let rhs_ty = rhs.ty(local_decls, tcx); | |
8bb4bdeb | 191 | op.ty(tcx, lhs_ty, rhs_ty) |
7453a54e | 192 | } |
6a06907d | 193 | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => { |
041b39d2 XL |
194 | let lhs_ty = lhs.ty(local_decls, tcx); |
195 | let rhs_ty = rhs.ty(local_decls, tcx); | |
5bcae85e | 196 | let ty = op.ty(tcx, lhs_ty, rhs_ty); |
0531ce1d | 197 | tcx.intern_tup(&[ty, tcx.types.bool]) |
3157f602 | 198 | } |
ba9703b0 | 199 | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), |
f9f354fc | 200 | Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), |
c295e0f8 | 201 | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, |
dfeec247 XL |
202 | Rvalue::Aggregate(ref ak, ref ops) => match **ak { |
203 | AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), | |
204 | AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))), | |
04454e1e FG |
205 | AggregateKind::Adt(did, _, substs, _, _) => { |
206 | tcx.bound_type_of(did).subst(tcx, substs) | |
207 | } | |
064997fb | 208 | AggregateKind::Closure(did, substs) => tcx.mk_closure(did.to_def_id(), substs), |
dfeec247 | 209 | AggregateKind::Generator(did, substs, movability) => { |
064997fb | 210 | tcx.mk_generator(did.to_def_id(), substs, movability) |
7453a54e | 211 | } |
dfeec247 | 212 | }, |
c295e0f8 | 213 | Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), |
064997fb | 214 | Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, |
5bcae85e SL |
215 | } |
216 | } | |
3b2f2976 XL |
217 | |
218 | #[inline] | |
9fa01778 | 219 | /// Returns `true` if this rvalue is deeply initialized (most rvalues) or |
3b2f2976 XL |
220 | /// whether its only shallowly initialized (`Rvalue::Box`). |
221 | pub fn initialization_state(&self) -> RvalueInitializationState { | |
222 | match *self { | |
a2a8927a | 223 | Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, |
dfeec247 | 224 | _ => RvalueInitializationState::Deep, |
3b2f2976 XL |
225 | } |
226 | } | |
5bcae85e SL |
227 | } |
228 | ||
229 | impl<'tcx> Operand<'tcx> { | |
dc9dc135 XL |
230 | pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> |
231 | where | |
232 | D: HasLocalDecls<'tcx>, | |
041b39d2 | 233 | { |
5bcae85e | 234 | match self { |
dfeec247 | 235 | &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, |
9c376795 | 236 | Operand::Constant(c) => c.literal.ty(), |
5bcae85e SL |
237 | } |
238 | } | |
239 | } | |
240 | ||
241 | impl<'tcx> BinOp { | |
dc9dc135 | 242 | pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> { |
5bcae85e SL |
243 | // FIXME: handle SIMD correctly |
244 | match self { | |
dfeec247 XL |
245 | &BinOp::Add |
246 | | &BinOp::Sub | |
247 | | &BinOp::Mul | |
248 | | &BinOp::Div | |
249 | | &BinOp::Rem | |
250 | | &BinOp::BitXor | |
251 | | &BinOp::BitAnd | |
252 | | &BinOp::BitOr => { | |
5bcae85e SL |
253 | // these should be integers or floats of the same size. |
254 | assert_eq!(lhs_ty, rhs_ty); | |
255 | lhs_ty | |
256 | } | |
7cac9316 | 257 | &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => { |
5bcae85e SL |
258 | lhs_ty // lhs_ty can be != rhs_ty |
259 | } | |
dfeec247 | 260 | &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { |
5bcae85e SL |
261 | tcx.types.bool |
262 | } | |
7453a54e SL |
263 | } |
264 | } | |
92a42be0 SL |
265 | } |
266 | ||
267 | impl BorrowKind { | |
268 | pub fn to_mutbl_lossy(self) -> hir::Mutability { | |
269 | match self { | |
dfeec247 XL |
270 | BorrowKind::Mut { .. } => hir::Mutability::Mut, |
271 | BorrowKind::Shared => hir::Mutability::Not, | |
92a42be0 SL |
272 | |
273 | // We have no type corresponding to a unique imm borrow, so | |
94222f64 | 274 | // use `&mut`. It gives all the capabilities of a `&uniq` |
92a42be0 | 275 | // and hence is a safe "over approximation". |
dfeec247 | 276 | BorrowKind::Unique => hir::Mutability::Mut, |
0bf4aa26 XL |
277 | |
278 | // We have no type corresponding to a shallow borrow, so use | |
279 | // `&` as an approximation. | |
dfeec247 | 280 | BorrowKind::Shallow => hir::Mutability::Not, |
92a42be0 SL |
281 | } |
282 | } | |
283 | } | |
284 | ||
285 | impl BinOp { | |
8faf50e0 | 286 | pub fn to_hir_binop(self) -> hir::BinOpKind { |
92a42be0 | 287 | match self { |
8faf50e0 XL |
288 | BinOp::Add => hir::BinOpKind::Add, |
289 | BinOp::Sub => hir::BinOpKind::Sub, | |
290 | BinOp::Mul => hir::BinOpKind::Mul, | |
291 | BinOp::Div => hir::BinOpKind::Div, | |
292 | BinOp::Rem => hir::BinOpKind::Rem, | |
293 | BinOp::BitXor => hir::BinOpKind::BitXor, | |
294 | BinOp::BitAnd => hir::BinOpKind::BitAnd, | |
295 | BinOp::BitOr => hir::BinOpKind::BitOr, | |
296 | BinOp::Shl => hir::BinOpKind::Shl, | |
297 | BinOp::Shr => hir::BinOpKind::Shr, | |
298 | BinOp::Eq => hir::BinOpKind::Eq, | |
299 | BinOp::Ne => hir::BinOpKind::Ne, | |
300 | BinOp::Lt => hir::BinOpKind::Lt, | |
301 | BinOp::Gt => hir::BinOpKind::Gt, | |
302 | BinOp::Le => hir::BinOpKind::Le, | |
303 | BinOp::Ge => hir::BinOpKind::Ge, | |
dfeec247 | 304 | BinOp::Offset => unreachable!(), |
92a42be0 SL |
305 | } |
306 | } | |
307 | } |