]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/mir_map.rs
Add `ScopeAuxiliaryVec`, return MIR+aux via tuple
[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 extern crate syntax;
20 extern crate rustc_front;
21
22 use build;
23 use rustc::dep_graph::DepNode;
24 use rustc::mir::repr::Mir;
25 use pretty;
26 use hair::cx::Cx;
27
28 use rustc::mir::mir_map::MirMap;
29 use rustc::middle::infer;
30 use rustc::middle::region::CodeExtentData;
31 use rustc::middle::traits::ProjectionMode;
32 use rustc::middle::ty::{self, Ty, TyCtxt};
33 use rustc::util::common::ErrorReported;
34 use rustc::util::nodemap::NodeMap;
35 use rustc_front::hir;
36 use rustc_front::intravisit::{self, Visitor};
37 use syntax::abi::Abi;
38 use syntax::ast;
39 use syntax::attr::AttrMetaMethods;
40 use syntax::codemap::Span;
41
42 pub fn build_mir_for_crate<'tcx>(tcx: &TyCtxt<'tcx>) -> MirMap<'tcx> {
43     let mut map = MirMap {
44         map: NodeMap(),
45     };
46     {
47         let mut dump = OuterDump {
48             tcx: tcx,
49             map: &mut map,
50         };
51         tcx.visit_all_items_in_krate(DepNode::MirMapConstruction, &mut dump);
52     }
53     map
54 }
55
56 ///////////////////////////////////////////////////////////////////////////
57 // OuterDump -- walks a crate, looking for fn items and methods to build MIR from
58
59 struct OuterDump<'a, 'tcx: 'a> {
60     tcx: &'a TyCtxt<'tcx>,
61     map: &'a mut MirMap<'tcx>,
62 }
63
64 impl<'a, 'tcx> OuterDump<'a, 'tcx> {
65     fn visit_mir<OP>(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP)
66         where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>)
67     {
68         let mut closure_dump = InnerDump {
69             tcx: self.tcx,
70             attr: None,
71             map: &mut *self.map,
72         };
73         for attr in attributes {
74             if attr.check_name("rustc_mir") {
75                 closure_dump.attr = Some(attr);
76             }
77         }
78         walk_op(&mut closure_dump);
79     }
80 }
81
82
83 impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> {
84     fn visit_item(&mut self, item: &'tcx hir::Item) {
85         self.visit_mir(&item.attrs, |c| intravisit::walk_item(c, item));
86         intravisit::walk_item(self, item);
87     }
88
89     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
90         match trait_item.node {
91             hir::MethodTraitItem(_, Some(_)) => {
92                 self.visit_mir(&trait_item.attrs, |c| intravisit::walk_trait_item(c, trait_item));
93             }
94             hir::MethodTraitItem(_, None) |
95             hir::ConstTraitItem(..) |
96             hir::TypeTraitItem(..) => {}
97         }
98         intravisit::walk_trait_item(self, trait_item);
99     }
100
101     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
102         match impl_item.node {
103             hir::ImplItemKind::Method(..) => {
104                 self.visit_mir(&impl_item.attrs, |c| intravisit::walk_impl_item(c, impl_item));
105             }
106             hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(..) => {}
107         }
108         intravisit::walk_impl_item(self, impl_item);
109     }
110 }
111
112 ///////////////////////////////////////////////////////////////////////////
113 // InnerDump -- dumps MIR for a single fn and its contained closures
114
115 struct InnerDump<'a, 'm, 'tcx: 'a + 'm> {
116     tcx: &'a TyCtxt<'tcx>,
117     map: &'m mut MirMap<'tcx>,
118     attr: Option<&'a ast::Attribute>,
119 }
120
121 impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
122     fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
123         // ignore methods; the outer dump will call us for them independently
124     }
125
126     fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
127         // ignore methods; the outer dump will call us for them independently
128     }
129
130     fn visit_fn(&mut self,
131                 fk: intravisit::FnKind<'tcx>,
132                 decl: &'tcx hir::FnDecl,
133                 body: &'tcx hir::Block,
134                 span: Span,
135                 id: ast::NodeId) {
136         let implicit_arg_tys = if let intravisit::FnKind::Closure(..) = fk {
137             vec![closure_self_ty(&self.tcx, id, body.id)]
138         } else {
139             vec![]
140         };
141
142         let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
143         let infcx = infer::new_infer_ctxt(self.tcx,
144                                           &self.tcx.tables,
145                                           Some(param_env),
146                                           ProjectionMode::AnyFinal);
147
148         match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
149             Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
150             Err(ErrorReported) => {}
151         }
152
153         intravisit::walk_fn(self, fk, decl, body, span);
154     }
155 }
156
157 fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
158                          implicit_arg_tys: Vec<Ty<'tcx>>,
159                          fn_id: ast::NodeId,
160                          span: Span,
161                          decl: &'tcx hir::FnDecl,
162                          body: &'tcx hir::Block)
163                          -> Result<Mir<'tcx>, ErrorReported> {
164     // fetch the fully liberated fn signature (that is, all bound
165     // types/lifetimes replaced)
166     let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
167         Some(f) => f.clone(),
168         None => {
169             cx.tcx().sess.span_bug(span,
170                                    &format!("no liberated fn sig for {:?}", fn_id));
171         }
172     };
173
174     let arguments =
175         decl.inputs
176             .iter()
177             .enumerate()
178             .map(|(index, arg)| {
179                 (fn_sig.inputs[index], &*arg.pat)
180             })
181             .collect();
182
183     let parameter_scope =
184         cx.tcx().region_maps.lookup_code_extent(
185             CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
186     let (mut mir, scope_auxiliary) =
187         build::construct(cx,
188                          span,
189                          implicit_arg_tys,
190                          arguments,
191                          parameter_scope,
192                          fn_sig.output,
193                          body);
194
195     match cx.tcx().node_id_to_type(fn_id).sty {
196         ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
197             // RustCall pseudo-ABI untuples the last argument.
198             if let Some(arg_decl) = mir.arg_decls.last_mut() {
199                 arg_decl.spread = true;
200             }
201         }
202         _ => {}
203     }
204
205     pretty::dump_mir(cx.tcx(),
206                      "mir_map",
207                      &0,
208                      fn_id,
209                      &mir,
210                      Some(&scope_auxiliary));
211
212     Ok(mir)
213 }
214
215 fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
216                              closure_expr_id: ast::NodeId,
217                              body_id: ast::NodeId)
218                              -> Ty<'tcx> {
219     let closure_ty = tcx.node_id_to_type(closure_expr_id);
220
221     // We're just hard-coding the idea that the signature will be
222     // &self or &mut self and hence will have a bound region with
223     // number 0, hokey.
224     let region = ty::Region::ReFree(ty::FreeRegion {
225         scope: tcx.region_maps.item_extent(body_id),
226         bound_region: ty::BoundRegion::BrAnon(0),
227     });
228     let region = tcx.mk_region(region);
229
230     match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
231         ty::ClosureKind::Fn =>
232             tcx.mk_ref(region,
233                        ty::TypeAndMut { ty: closure_ty,
234                                         mutbl: hir::MutImmutable }),
235         ty::ClosureKind::FnMut =>
236             tcx.mk_ref(region,
237                        ty::TypeAndMut { ty: closure_ty,
238                                         mutbl: hir::MutMutable }),
239         ty::ClosureKind::FnOnce =>
240             closure_ty
241     }
242 }