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