]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/mir_map.rs
Rollup merge of #35558 - lukehinds:master, r=nikomatsakis
[rust.git] / src / librustc_mir / mir_map.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 //! An experimental pass that scources for `#[rustc_mir]` attributes,
12 //! builds the resulting MIR, and dumps it out into a file for inspection.
13 //!
14 //! The attribute formats that are currently accepted are:
15 //!
16 //! - `#[rustc_mir(graphviz="file.gv")]`
17 //! - `#[rustc_mir(pretty="file.mir")]`
18
19 use build;
20 use rustc::dep_graph::DepNode;
21 use rustc::hir::def_id::DefId;
22 use rustc::mir::repr::Mir;
23 use rustc::mir::transform::MirSource;
24 use rustc::mir::visit::MutVisitor;
25 use pretty;
26 use hair::cx::Cx;
27
28 use rustc::mir::mir_map::MirMap;
29 use rustc::infer::InferCtxtBuilder;
30 use rustc::traits::Reveal;
31 use rustc::ty::{self, Ty, TyCtxt};
32 use rustc::ty::subst::Substs;
33 use rustc::hir;
34 use rustc::hir::intravisit::{self, FnKind, Visitor};
35 use syntax::ast;
36 use syntax_pos::Span;
37
38 use std::mem;
39
40 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx> {
41     let mut map = MirMap::new(tcx.dep_graph.clone());
42     {
43         let mut dump = BuildMir {
44             tcx: tcx,
45             map: &mut map,
46         };
47         tcx.visit_all_items_in_krate(DepNode::Mir, &mut dump);
48     }
49     map
50 }
51
52 /// A pass to lift all the types and substitutions in a Mir
53 /// to the global tcx. Sadly, we don't have a "folder" that
54 /// can change 'tcx so we have to transmute afterwards.
55 struct GlobalizeMir<'a, 'gcx: 'a> {
56     tcx: TyCtxt<'a, 'gcx, 'gcx>,
57     span: Span
58 }
59
60 impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
61     fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
62         if let Some(lifted) = self.tcx.lift(ty) {
63             *ty = lifted;
64         } else {
65             span_bug!(self.span,
66                       "found type `{:?}` with inference types/regions in MIR",
67                       ty);
68         }
69     }
70
71     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
72         if let Some(lifted) = self.tcx.lift(substs) {
73             *substs = lifted;
74         } else {
75             span_bug!(self.span,
76                       "found substs `{:?}` with inference types/regions in MIR",
77                       substs);
78         }
79     }
80 }
81
82 ///////////////////////////////////////////////////////////////////////////
83 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
84
85 struct BuildMir<'a, 'tcx: 'a> {
86     tcx: TyCtxt<'a, 'tcx, 'tcx>,
87     map: &'a mut MirMap<'tcx>,
88 }
89
90 /// Helper type of a temporary returned by BuildMir::cx(...).
91 /// Necessary because we can't write the following bound:
92 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Cx<'b, 'gcx, 'tcx>).
93 struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
94     src: MirSource,
95     def_id: DefId,
96     infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>,
97     map: &'a mut MirMap<'gcx>,
98 }
99
100 impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> {
101     fn cx<'b>(&'b mut self, src: MirSource) -> CxBuilder<'b, 'gcx, 'tcx> {
102         let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
103         let def_id = self.tcx.map.local_def_id(src.item_id());
104         CxBuilder {
105             src: src,
106             infcx: self.tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable),
107             def_id: def_id,
108             map: self.map
109         }
110     }
111 }
112
113 impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
114     fn build<F>(&'tcx mut self, f: F)
115         where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
116     {
117         let src = self.src;
118         let mir = self.infcx.enter(|infcx| {
119             let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, src));
120
121             // Convert the Mir to global types.
122             let mut globalizer = GlobalizeMir {
123                 tcx: infcx.tcx.global_tcx(),
124                 span: mir.span
125             };
126             globalizer.visit_mir(&mut mir);
127             let mir = unsafe {
128                 mem::transmute::<Mir, Mir<'gcx>>(mir)
129             };
130
131             pretty::dump_mir(infcx.tcx.global_tcx(), "mir_map", &0,
132                              src, &mir, Some(&scope_auxiliary));
133
134             mir
135         });
136
137         assert!(self.map.map.insert(self.def_id, mir).is_none())
138     }
139 }
140
141 impl<'a, 'gcx> BuildMir<'a, 'gcx> {
142     fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
143         // FIXME(eddyb) Closures should have separate
144         // function definition IDs and expression IDs.
145         // Type-checking should not let closures get
146         // this far in an integer constant position.
147         if let hir::ExprClosure(..) = expr.node {
148             return;
149         }
150         self.cx(MirSource::Const(expr.id)).build(|cx| {
151             build::construct_const(cx, expr.id, expr)
152         });
153     }
154 }
155
156 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
157     // Const and static items.
158     fn visit_item(&mut self, item: &'tcx hir::Item) {
159         match item.node {
160             hir::ItemConst(_, ref expr) => {
161                 self.cx(MirSource::Const(item.id)).build(|cx| {
162                     build::construct_const(cx, item.id, expr)
163                 });
164             }
165             hir::ItemStatic(_, m, ref expr) => {
166                 self.cx(MirSource::Static(item.id, m)).build(|cx| {
167                     build::construct_const(cx, item.id, expr)
168                 });
169             }
170             _ => {}
171         }
172         intravisit::walk_item(self, item);
173     }
174
175     // Trait associated const defaults.
176     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
177         if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
178             self.cx(MirSource::Const(item.id)).build(|cx| {
179                 build::construct_const(cx, item.id, expr)
180             });
181         }
182         intravisit::walk_trait_item(self, item);
183     }
184
185     // Impl associated const.
186     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
187         if let hir::ImplItemKind::Const(_, ref expr) = item.node {
188             self.cx(MirSource::Const(item.id)).build(|cx| {
189                 build::construct_const(cx, item.id, expr)
190             });
191         }
192         intravisit::walk_impl_item(self, item);
193     }
194
195     // Repeat counts, i.e. [expr; constant].
196     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
197         if let hir::ExprRepeat(_, ref count) = expr.node {
198             self.build_const_integer(count);
199         }
200         intravisit::walk_expr(self, expr);
201     }
202
203     // Array lengths, i.e. [T; constant].
204     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
205         if let hir::TyFixedLengthVec(_, ref length) = ty.node {
206             self.build_const_integer(length);
207         }
208         intravisit::walk_ty(self, ty);
209     }
210
211     // Enum variant discriminant values.
212     fn visit_variant(&mut self, v: &'tcx hir::Variant,
213                      g: &'tcx hir::Generics, item_id: ast::NodeId) {
214         if let Some(ref expr) = v.node.disr_expr {
215             self.build_const_integer(expr);
216         }
217         intravisit::walk_variant(self, v, g, item_id);
218     }
219
220     fn visit_fn(&mut self,
221                 fk: FnKind<'tcx>,
222                 decl: &'tcx hir::FnDecl,
223                 body: &'tcx hir::Block,
224                 span: Span,
225                 id: ast::NodeId) {
226         // fetch the fully liberated fn signature (that is, all bound
227         // types/lifetimes replaced)
228         let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) {
229             Some(f) => f.clone(),
230             None => {
231                 span_bug!(span, "no liberated fn sig for {:?}", id);
232             }
233         };
234
235         let implicit_argument = if let FnKind::Closure(..) = fk {
236             Some((closure_self_ty(self.tcx, id, body.id), None))
237         } else {
238             None
239         };
240
241         let explicit_arguments =
242             decl.inputs
243                 .iter()
244                 .enumerate()
245                 .map(|(index, arg)| {
246                     (fn_sig.inputs[index], Some(&*arg.pat))
247                 });
248
249         let arguments = implicit_argument.into_iter().chain(explicit_arguments);
250         self.cx(MirSource::Fn(id)).build(|cx| {
251             build::construct_fn(cx, id, arguments, fn_sig.output, body)
252         });
253
254         intravisit::walk_fn(self, fk, decl, body, span, id);
255     }
256 }
257
258 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
259                              closure_expr_id: ast::NodeId,
260                              body_id: ast::NodeId)
261                              -> Ty<'tcx> {
262     let closure_ty = tcx.node_id_to_type(closure_expr_id);
263
264     // We're just hard-coding the idea that the signature will be
265     // &self or &mut self and hence will have a bound region with
266     // number 0, hokey.
267     let region = ty::Region::ReFree(ty::FreeRegion {
268         scope: tcx.region_maps.item_extent(body_id),
269         bound_region: ty::BoundRegion::BrAnon(0),
270     });
271     let region = tcx.mk_region(region);
272
273     match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
274         ty::ClosureKind::Fn =>
275             tcx.mk_ref(region,
276                        ty::TypeAndMut { ty: closure_ty,
277                                         mutbl: hir::MutImmutable }),
278         ty::ClosureKind::FnMut =>
279             tcx.mk_ref(region,
280                        ty::TypeAndMut { ty: closure_ty,
281                                         mutbl: hir::MutMutable }),
282         ty::ClosureKind::FnOnce =>
283             closure_ty
284     }
285 }