]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/tcx/mod.rs
4d034ae23b49a05dfe9ed01c829510086df20235
[rust.git] / src / librustc_mir / tcx / mod.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  * Methods for the various MIR types. These are intended for use after
13  * building is complete.
14  */
15
16 use repr::*;
17 use rustc::middle::subst::Substs;
18 use rustc::middle::ty::{self, AdtDef, Ty};
19 use rustc_front::hir;
20
21 #[derive(Copy, Clone, Debug)]
22 pub enum LvalueTy<'tcx> {
23     /// Normal type.
24     Ty { ty: Ty<'tcx> },
25
26     /// Downcast to a particular variant of an enum.
27     Downcast { adt_def: AdtDef<'tcx>,
28                substs: &'tcx Substs<'tcx>,
29                variant_index: usize },
30 }
31
32 impl<'tcx> LvalueTy<'tcx> {
33     pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
34         LvalueTy::Ty { ty: ty }
35     }
36
37     pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
38         match *self {
39             LvalueTy::Ty { ty } =>
40                 ty,
41             LvalueTy::Downcast { adt_def, substs, variant_index: _ } =>
42                 tcx.mk_enum(adt_def, substs),
43         }
44     }
45
46     pub fn projection_ty(self,
47                          tcx: &ty::ctxt<'tcx>,
48                          elem: &LvalueElem<'tcx>)
49                          -> LvalueTy<'tcx>
50     {
51         match *elem {
52             ProjectionElem::Deref =>
53                 LvalueTy::Ty {
54                     ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference)
55                                           .unwrap()
56                                           .ty
57                 },
58             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
59                 LvalueTy::Ty {
60                     ty: self.to_ty(tcx).builtin_index().unwrap()
61                 },
62             ProjectionElem::Downcast(adt_def1, index) =>
63                 match self.to_ty(tcx).sty {
64                     ty::TyEnum(adt_def, substs) => {
65                         assert!(index < adt_def.variants.len());
66                         assert_eq!(adt_def, adt_def1);
67                         LvalueTy::Downcast { adt_def: adt_def,
68                                              substs: substs,
69                                              variant_index: index }
70                     }
71                     _ => {
72                         tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
73                     }
74                 },
75             ProjectionElem::Field(field) => {
76                 let field_ty = match self {
77                     LvalueTy::Ty { ty } => match ty.sty {
78                         ty::TyStruct(adt_def, substs) =>
79                             adt_def.struct_variant().fields[field.index()].ty(tcx, substs),
80                         ty::TyTuple(ref tys) =>
81                             tys[field.index()],
82                         ty::TyClosure(_, ref closure_substs) =>
83                             closure_substs.upvar_tys[field.index()],
84                         _ =>
85                             tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)),
86                     },
87                     LvalueTy::Downcast { adt_def, substs, variant_index } =>
88                         adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs),
89                 };
90                 LvalueTy::Ty { ty: field_ty }
91             }
92         }
93     }
94 }
95
96 impl<'tcx> Mir<'tcx> {
97     pub fn operand_ty(&self,
98                       tcx: &ty::ctxt<'tcx>,
99                       operand: &Operand<'tcx>)
100                       -> Ty<'tcx>
101     {
102         match *operand {
103             Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx),
104             Operand::Constant(ref c) => c.ty,
105         }
106     }
107
108     pub fn binop_ty(&self,
109                     tcx: &ty::ctxt<'tcx>,
110                     op: BinOp,
111                     lhs_ty: Ty<'tcx>,
112                     rhs_ty: Ty<'tcx>)
113                     -> Ty<'tcx>
114     {
115         // FIXME: handle SIMD correctly
116         match op {
117             BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem |
118             BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr => {
119                 // these should be integers or floats of the same size.
120                 assert_eq!(lhs_ty, rhs_ty);
121                 lhs_ty
122             }
123             BinOp::Shl | BinOp::Shr => {
124                 lhs_ty // lhs_ty can be != rhs_ty
125             }
126             BinOp::Eq | BinOp::Lt | BinOp::Le |
127             BinOp::Ne | BinOp::Ge | BinOp::Gt => {
128                 tcx.types.bool
129             }
130         }
131     }
132
133     pub fn lvalue_ty(&self,
134                      tcx: &ty::ctxt<'tcx>,
135                      lvalue: &Lvalue<'tcx>)
136                      -> LvalueTy<'tcx>
137     {
138         match *lvalue {
139             Lvalue::Var(index) =>
140                 LvalueTy::Ty { ty: self.var_decls[index as usize].ty },
141             Lvalue::Temp(index) =>
142                 LvalueTy::Ty { ty: self.temp_decls[index as usize].ty },
143             Lvalue::Arg(index) =>
144                 LvalueTy::Ty { ty: self.arg_decls[index as usize].ty },
145             Lvalue::Static(def_id) =>
146                 LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
147             Lvalue::ReturnPointer =>
148                 LvalueTy::Ty { ty: self.return_ty.unwrap() },
149             Lvalue::Projection(ref proj) =>
150                 self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
151         }
152     }
153 }
154
155 impl BorrowKind {
156     pub fn to_mutbl_lossy(self) -> hir::Mutability {
157         match self {
158             BorrowKind::Mut => hir::MutMutable,
159             BorrowKind::Shared => hir::MutImmutable,
160
161             // We have no type corresponding to a unique imm borrow, so
162             // use `&mut`. It gives all the capabilities of an `&uniq`
163             // and hence is a safe "over approximation".
164             BorrowKind::Unique => hir::MutMutable,
165         }
166     }
167 }
168
169 impl BinOp {
170     pub fn to_hir_binop(self) -> hir::BinOp_ {
171         match self {
172             BinOp::Add => hir::BinOp_::BiAdd,
173             BinOp::Sub => hir::BinOp_::BiSub,
174             BinOp::Mul => hir::BinOp_::BiMul,
175             BinOp::Div => hir::BinOp_::BiDiv,
176             BinOp::Rem => hir::BinOp_::BiRem,
177             BinOp::BitXor => hir::BinOp_::BiBitXor,
178             BinOp::BitAnd => hir::BinOp_::BiBitAnd,
179             BinOp::BitOr => hir::BinOp_::BiBitOr,
180             BinOp::Shl => hir::BinOp_::BiShl,
181             BinOp::Shr => hir::BinOp_::BiShr,
182             BinOp::Eq => hir::BinOp_::BiEq,
183             BinOp::Ne => hir::BinOp_::BiNe,
184             BinOp::Lt => hir::BinOp_::BiLt,
185             BinOp::Gt => hir::BinOp_::BiGt,
186             BinOp::Le => hir::BinOp_::BiLe,
187             BinOp::Ge => hir::BinOp_::BiGe
188         }
189     }
190 }