]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/mir_map.rs
6aa7089e7a9069d37bbe11acef3ad16fa179f095
[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::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
21 use rustc::dep_graph::DepNode;
22 use rustc::mir::Mir;
23 use rustc::mir::transform::MirSource;
24 use rustc::mir::visit::MutVisitor;
25 use shim;
26 use hair::cx::Cx;
27 use util as mir_util;
28
29 use rustc::traits::Reveal;
30 use rustc::ty::{self, Ty, TyCtxt};
31 use rustc::ty::maps::Providers;
32 use rustc::ty::subst::Substs;
33 use rustc::hir;
34 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
35 use rustc::util::nodemap::DefIdSet;
36 use syntax::abi::Abi;
37 use syntax::ast;
38 use syntax_pos::Span;
39
40 use std::cell::RefCell;
41 use std::mem;
42 use std::rc::Rc;
43
44 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
45     tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task);
46
47     fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
48         for &body_owner_def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
49             tcx.item_mir(body_owner_def_id);
50         }
51     }
52 }
53
54 pub fn provide(providers: &mut Providers) {
55     providers.mir = build_mir;
56     providers.mir_keys = mir_keys;
57 }
58
59 fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
60                       -> Rc<DefIdSet> {
61     assert_eq!(krate, LOCAL_CRATE);
62
63     let mut set = DefIdSet();
64
65     // All body-owners have MIR associated with them.
66     set.extend(tcx.body_owners());
67
68     // Additionally, tuple struct/variant constructors have MIR, but
69     // they don't have a BodyId, so we need to build them separately.
70     struct GatherCtors<'a, 'tcx: 'a> {
71         tcx: TyCtxt<'a, 'tcx, 'tcx>,
72         set: &'a mut DefIdSet,
73     }
74     impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
75         fn visit_variant_data(&mut self,
76                               v: &'tcx hir::VariantData,
77                               _: ast::Name,
78                               _: &'tcx hir::Generics,
79                               _: ast::NodeId,
80                               _: Span) {
81             if let hir::VariantData::Tuple(_, node_id) = *v {
82                 self.set.insert(self.tcx.hir.local_def_id(node_id));
83             }
84             intravisit::walk_struct_def(self, v)
85         }
86         fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
87             NestedVisitorMap::None
88         }
89     }
90     tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
91         tcx: tcx,
92         set: &mut set,
93     }.as_deep_visitor());
94
95     Rc::new(set)
96 }
97
98 fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
99                        -> &'tcx RefCell<Mir<'tcx>> {
100     let id = tcx.hir.as_local_node_id(def_id).unwrap();
101     let unsupported = || {
102         span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
103     };
104
105     // Figure out what primary body this item has.
106     let body_id = match tcx.hir.get(id) {
107         hir::map::NodeItem(item) => {
108             match item.node {
109                 hir::ItemConst(_, body) |
110                 hir::ItemStatic(_, _, body) |
111                 hir::ItemFn(.., body) => body,
112                 _ => unsupported()
113             }
114         }
115         hir::map::NodeTraitItem(item) => {
116             match item.node {
117                 hir::TraitItemKind::Const(_, Some(body)) |
118                 hir::TraitItemKind::Method(_,
119                     hir::TraitMethod::Provided(body)) => body,
120                 _ => unsupported()
121             }
122         }
123         hir::map::NodeImplItem(item) => {
124             match item.node {
125                 hir::ImplItemKind::Const(_, body) |
126                 hir::ImplItemKind::Method(_, body) => body,
127                 _ => unsupported()
128             }
129         }
130         hir::map::NodeExpr(expr) => {
131             // FIXME(eddyb) Closures should have separate
132             // function definition IDs and expression IDs.
133             // Type-checking should not let closures get
134             // this far in a constant position.
135             // Assume that everything other than closures
136             // is a constant "initializer" expression.
137             match expr.node {
138                 hir::ExprClosure(_, _, body, _) => body,
139                 _ => hir::BodyId { node_id: expr.id }
140             }
141         }
142         hir::map::NodeVariant(variant) =>
143             return create_constructor_shim(tcx, id, &variant.node.data),
144         hir::map::NodeStructCtor(ctor) =>
145             return create_constructor_shim(tcx, id, ctor),
146         _ => unsupported()
147     };
148
149     let src = MirSource::from_node(tcx, id);
150     tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
151         let cx = Cx::new(&infcx, src);
152         let mut mir = if cx.tables().tainted_by_errors {
153             build::construct_error(cx, body_id)
154         } else if let MirSource::Fn(id) = src {
155             // fetch the fully liberated fn signature (that is, all bound
156             // types/lifetimes replaced)
157             let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
158
159             let ty = tcx.type_of(tcx.hir.local_def_id(id));
160             let mut abi = fn_sig.abi;
161             let implicit_argument = if let ty::TyClosure(..) = ty.sty {
162                 // HACK(eddyb) Avoid having RustCall on closures,
163                 // as it adds unnecessary (and wrong) auto-tupling.
164                 abi = Abi::Rust;
165                 Some((closure_self_ty(tcx, id, body_id), None))
166             } else {
167                 None
168             };
169
170             let body = tcx.hir.body(body_id);
171             let explicit_arguments =
172                 body.arguments
173                     .iter()
174                     .enumerate()
175                     .map(|(index, arg)| {
176                         (fn_sig.inputs()[index], Some(&*arg.pat))
177                     });
178
179             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
180             build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
181         } else {
182             build::construct_const(cx, body_id)
183         };
184
185         // Convert the Mir to global types.
186         let mut globalizer = GlobalizeMir {
187             tcx: tcx,
188             span: mir.span
189         };
190         globalizer.visit_mir(&mut mir);
191         let mir = unsafe {
192             mem::transmute::<Mir, Mir<'tcx>>(mir)
193         };
194
195         mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
196
197         tcx.alloc_mir(mir)
198     })
199 }
200
201 /// A pass to lift all the types and substitutions in a Mir
202 /// to the global tcx. Sadly, we don't have a "folder" that
203 /// can change 'tcx so we have to transmute afterwards.
204 struct GlobalizeMir<'a, 'gcx: 'a> {
205     tcx: TyCtxt<'a, 'gcx, 'gcx>,
206     span: Span
207 }
208
209 impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
210     fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
211         if let Some(lifted) = self.tcx.lift(ty) {
212             *ty = lifted;
213         } else {
214             span_bug!(self.span,
215                       "found type `{:?}` with inference types/regions in MIR",
216                       ty);
217         }
218     }
219
220     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
221         if let Some(lifted) = self.tcx.lift(substs) {
222             *substs = lifted;
223         } else {
224             span_bug!(self.span,
225                       "found substs `{:?}` with inference types/regions in MIR",
226                       substs);
227         }
228     }
229 }
230
231 fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
232                                      ctor_id: ast::NodeId,
233                                      v: &'tcx hir::VariantData)
234                                      -> &'tcx RefCell<Mir<'tcx>>
235 {
236     let span = tcx.hir.span(ctor_id);
237     if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
238         let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
239         tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
240             let (mut mir, src) =
241                 shim::build_adt_ctor(&infcx, ctor_id, fields, span);
242
243             // Convert the Mir to global types.
244             let tcx = infcx.tcx.global_tcx();
245             let mut globalizer = GlobalizeMir {
246                 tcx: tcx,
247                 span: mir.span
248             };
249             globalizer.visit_mir(&mut mir);
250             let mir = unsafe {
251                 mem::transmute::<Mir, Mir<'tcx>>(mir)
252             };
253
254             mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
255
256             tcx.alloc_mir(mir)
257         })
258     } else {
259         span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
260     }
261 }
262
263 ///////////////////////////////////////////////////////////////////////////
264 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
265
266 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
267                              closure_expr_id: ast::NodeId,
268                              body_id: hir::BodyId)
269                              -> Ty<'tcx> {
270     let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
271
272     let region = ty::ReFree(ty::FreeRegion {
273         scope: Some(tcx.item_extent(body_id.node_id)),
274         bound_region: ty::BoundRegion::BrEnv,
275     });
276     let region = tcx.mk_region(region);
277
278     match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
279         ty::ClosureKind::Fn =>
280             tcx.mk_ref(region,
281                        ty::TypeAndMut { ty: closure_ty,
282                                         mutbl: hir::MutImmutable }),
283         ty::ClosureKind::FnMut =>
284             tcx.mk_ref(region,
285                        ty::TypeAndMut { ty: closure_ty,
286                                         mutbl: hir::MutMutable }),
287         ty::ClosureKind::FnOnce =>
288             closure_ty
289     }
290 }