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