2 * Methods for the various MIR types. These are intended for use after
3 * building is complete.
7 use crate::ty
::subst
::Subst
;
8 use crate::ty
::{self, Ty, TyCtxt}
;
10 use rustc_target
::abi
::VariantIdx
;
12 #[derive(Copy, Clone, Debug, TypeFoldable)]
13 pub struct PlaceTy
<'tcx
> {
15 /// Downcast to a particular variant of an enum, if included.
16 pub variant_index
: Option
<VariantIdx
>,
19 // At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
20 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
21 static_assert_size
!(PlaceTy
<'_
>, 16);
23 impl<'tcx
> PlaceTy
<'tcx
> {
25 pub fn from_ty(ty
: Ty
<'tcx
>) -> PlaceTy
<'tcx
> {
26 PlaceTy { ty, variant_index: None }
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`.)
35 /// Note that the resulting type has not been normalized.
36 pub fn field_ty(self, tcx
: TyCtxt
<'tcx
>, f
: &Field
) -> Ty
<'tcx
> {
37 let answer
= match self.ty
.kind() {
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
]
46 let field_def
= &variant_def
.fields
[f
.index()];
47 field_def
.ty(tcx
, substs
)
49 ty
::Tuple(ref tys
) => tys
[f
.index()].expect_ty(),
50 _
=> bug
!("extracting field of non-tuple non-adt: {:?}", self),
52 debug
!("field_ty self: {:?} f: {:?} yields: {:?}", self, f
, answer
);
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.
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
)
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`).
68 pub fn projection_ty_core
<V
, T
>(
71 param_env
: ty
::ParamEnv
<'tcx
>,
72 elem
: &ProjectionElem
<V
, T
>,
73 mut handle_field
: impl FnMut(&Self, &Field
, &T
) -> Ty
<'tcx
>,
79 let answer
= match *elem
{
80 ProjectionElem
::Deref
=> {
85 bug
!("deref projection of non-dereferenceable ty {:?}", self)
90 ProjectionElem
::Index(_
) | ProjectionElem
::ConstantIndex { .. }
=> {
91 PlaceTy
::from_ty(self.ty
.builtin_index().unwrap())
93 ProjectionElem
::Subslice { from, to, from_end }
=> {
94 PlaceTy
::from_ty(match self.ty
.kind() {
95 ty
::Slice(..) => self.ty
,
96 ty
::Array(inner
, _
) if !from_end
=> tcx
.mk_array(inner
, (to
- from
) as u64),
97 ty
::Array(inner
, size
) if from_end
=> {
98 let size
= size
.eval_usize(tcx
, param_env
);
99 let len
= size
- (from
as u64) - (to
as u64);
100 tcx
.mk_array(inner
, len
)
102 _
=> bug
!("cannot subslice non-array type: `{:?}`", self),
105 ProjectionElem
::Downcast(_name
, index
) => {
106 PlaceTy { ty: self.ty, variant_index: Some(index) }
108 ProjectionElem
::Field(ref f
, ref fty
) => PlaceTy
::from_ty(handle_field(&self, f
, fty
)),
110 debug
!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem
, answer
);
115 impl<'tcx
> Place
<'tcx
> {
118 projection
: &[PlaceElem
<'tcx
>],
123 D
: HasLocalDecls
<'tcx
>,
127 .fold(PlaceTy
::from_ty(local_decls
.local_decls()[local
].ty
), |place_ty
, &elem
| {
128 place_ty
.projection_ty(tcx
, elem
)
132 pub fn ty
<D
>(&self, local_decls
: &D
, tcx
: TyCtxt
<'tcx
>) -> PlaceTy
<'tcx
>
134 D
: HasLocalDecls
<'tcx
>,
136 Place
::ty_from(self.local
, &self.projection
, local_decls
, tcx
)
140 impl<'tcx
> PlaceRef
<'tcx
> {
141 pub fn ty
<D
>(&self, local_decls
: &D
, tcx
: TyCtxt
<'tcx
>) -> PlaceTy
<'tcx
>
143 D
: HasLocalDecls
<'tcx
>,
145 Place
::ty_from(self.local
, &self.projection
, local_decls
, tcx
)
149 pub enum RvalueInitializationState
{
154 impl<'tcx
> Rvalue
<'tcx
> {
155 pub fn ty
<D
>(&self, local_decls
: &D
, tcx
: TyCtxt
<'tcx
>) -> Ty
<'tcx
>
157 D
: HasLocalDecls
<'tcx
>,
160 Rvalue
::Use(ref operand
) => operand
.ty(local_decls
, tcx
),
161 Rvalue
::Repeat(ref operand
, count
) => {
162 tcx
.mk_ty(ty
::Array(operand
.ty(local_decls
, tcx
), count
))
164 Rvalue
::ThreadLocalRef(did
) => {
165 let static_ty
= tcx
.type_of(did
);
166 if tcx
.is_mutable_static(did
) {
167 tcx
.mk_mut_ptr(static_ty
)
168 } else if tcx
.is_foreign_item(did
) {
169 tcx
.mk_imm_ptr(static_ty
)
171 // FIXME: These things don't *really* have 'static lifetime.
172 tcx
.mk_imm_ref(tcx
.lifetimes
.re_static
, static_ty
)
175 Rvalue
::Ref(reg
, bk
, ref place
) => {
176 let place_ty
= place
.ty(local_decls
, tcx
).ty
;
177 tcx
.mk_ref(reg
, ty
::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }
)
179 Rvalue
::AddressOf(mutability
, ref place
) => {
180 let place_ty
= place
.ty(local_decls
, tcx
).ty
;
181 tcx
.mk_ptr(ty
::TypeAndMut { ty: place_ty, mutbl: mutability }
)
183 Rvalue
::Len(..) => tcx
.types
.usize,
184 Rvalue
::Cast(.., ty
) => ty
,
185 Rvalue
::BinaryOp(op
, box (ref lhs
, ref rhs
)) => {
186 let lhs_ty
= lhs
.ty(local_decls
, tcx
);
187 let rhs_ty
= rhs
.ty(local_decls
, tcx
);
188 op
.ty(tcx
, lhs_ty
, rhs_ty
)
190 Rvalue
::CheckedBinaryOp(op
, box (ref lhs
, ref rhs
)) => {
191 let lhs_ty
= lhs
.ty(local_decls
, tcx
);
192 let rhs_ty
= rhs
.ty(local_decls
, tcx
);
193 let ty
= op
.ty(tcx
, lhs_ty
, rhs_ty
);
194 tcx
.intern_tup(&[ty
, tcx
.types
.bool
])
196 Rvalue
::UnaryOp(UnOp
::Not
| UnOp
::Neg
, ref operand
) => operand
.ty(local_decls
, tcx
),
197 Rvalue
::Discriminant(ref place
) => place
.ty(local_decls
, tcx
).ty
.discriminant_ty(tcx
),
198 Rvalue
::NullaryOp(NullOp
::Box
, t
) => tcx
.mk_box(t
),
199 Rvalue
::NullaryOp(NullOp
::SizeOf
| NullOp
::AlignOf
, _
) => tcx
.types
.usize,
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
)
209 Rvalue
::ShallowInitBox(_
, ty
) => tcx
.mk_box(ty
),
214 /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
215 /// whether its only shallowly initialized (`Rvalue::Box`).
216 pub fn initialization_state(&self) -> RvalueInitializationState
{
218 Rvalue
::NullaryOp(NullOp
::Box
, _
) | Rvalue
::ShallowInitBox(_
, _
) => {
219 RvalueInitializationState
::Shallow
221 _
=> RvalueInitializationState
::Deep
,
226 impl<'tcx
> Operand
<'tcx
> {
227 pub fn ty
<D
>(&self, local_decls
: &D
, tcx
: TyCtxt
<'tcx
>) -> Ty
<'tcx
>
229 D
: HasLocalDecls
<'tcx
>,
232 &Operand
::Copy(ref l
) | &Operand
::Move(ref l
) => l
.ty(local_decls
, tcx
).ty
,
233 &Operand
::Constant(ref c
) => c
.literal
.ty(),
239 pub fn ty(&self, tcx
: TyCtxt
<'tcx
>, lhs_ty
: Ty
<'tcx
>, rhs_ty
: Ty
<'tcx
>) -> Ty
<'tcx
> {
240 // FIXME: handle SIMD correctly
250 // these should be integers or floats of the same size.
251 assert_eq
!(lhs_ty
, rhs_ty
);
254 &BinOp
::Shl
| &BinOp
::Shr
| &BinOp
::Offset
=> {
255 lhs_ty
// lhs_ty can be != rhs_ty
257 &BinOp
::Eq
| &BinOp
::Lt
| &BinOp
::Le
| &BinOp
::Ne
| &BinOp
::Ge
| &BinOp
::Gt
=> {
265 pub fn to_mutbl_lossy(self) -> hir
::Mutability
{
267 BorrowKind
::Mut { .. }
=> hir
::Mutability
::Mut
,
268 BorrowKind
::Shared
=> hir
::Mutability
::Not
,
270 // We have no type corresponding to a unique imm borrow, so
271 // use `&mut`. It gives all the capabilities of a `&uniq`
272 // and hence is a safe "over approximation".
273 BorrowKind
::Unique
=> hir
::Mutability
::Mut
,
275 // We have no type corresponding to a shallow borrow, so use
276 // `&` as an approximation.
277 BorrowKind
::Shallow
=> hir
::Mutability
::Not
,
283 pub fn to_hir_binop(self) -> hir
::BinOpKind
{
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
,
301 BinOp
::Offset
=> unreachable
!(),