//! - `#[rustc_mir(pretty="file.mir")]`
use build;
+use rustc::hir::def_id::DefId;
use rustc::dep_graph::DepNode;
use rustc::mir::Mir;
use rustc::mir::transform::MirSource;
use pretty;
use hair::cx::Cx;
-use rustc::infer::InferCtxt;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
use rustc::ty::subst::Substs;
use rustc::hir;
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use syntax::ast;
use syntax_pos::Span;
+use std::cell::RefCell;
use std::mem;
pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
}.as_deep_visitor());
}
+pub fn provide(providers: &mut Providers) {
+ providers.mir = build_mir;
+}
+
+fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> &'tcx RefCell<Mir<'tcx>> {
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let unsupported = || {
+ span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
+ };
+
+ // Figure out what primary body this item has.
+ let body_id = match tcx.hir.get(id) {
+ hir::map::NodeItem(item) => {
+ match item.node {
+ hir::ItemConst(_, body) |
+ hir::ItemStatic(_, _, body) |
+ hir::ItemFn(.., body) => body,
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeTraitItem(item) => {
+ match item.node {
+ hir::TraitItemKind::Const(_, Some(body)) |
+ hir::TraitItemKind::Method(_,
+ hir::TraitMethod::Provided(body)) => body,
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeImplItem(item) => {
+ match item.node {
+ hir::ImplItemKind::Const(_, body) |
+ hir::ImplItemKind::Method(_, body) => body,
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeExpr(expr) => {
+ // FIXME(eddyb) Closures should have separate
+ // function definition IDs and expression IDs.
+ // Type-checking should not let closures get
+ // this far in a constant position.
+ // Assume that everything other than closures
+ // is a constant "initializer" expression.
+ match expr.node {
+ hir::ExprClosure(_, _, body, _) => body,
+ _ => hir::BodyId { node_id: expr.id }
+ }
+ }
+ _ => unsupported()
+ };
+
+ let src = MirSource::from_node(tcx, id);
+ tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+ let cx = Cx::new(&infcx, src);
+ let mut mir = if let MirSource::Fn(id) = src {
+ // fetch the fully liberated fn signature (that is, all bound
+ // types/lifetimes replaced)
+ let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
+
+ let ty = tcx.item_type(tcx.hir.local_def_id(id));
+ let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
+ (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
+ } else {
+ (ty.fn_abi(), None)
+ };
+
+ let body = tcx.hir.body(body_id);
+ let explicit_arguments =
+ body.arguments
+ .iter()
+ .enumerate()
+ .map(|(index, arg)| {
+ (fn_sig.inputs()[index], Some(&*arg.pat))
+ });
+
+ let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+ build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
+ } else {
+ build::construct_const(cx, body_id)
+ };
+
+ // Convert the Mir to global types.
+ let mut globalizer = GlobalizeMir {
+ tcx: tcx,
+ span: mir.span
+ };
+ globalizer.visit_mir(&mut mir);
+ let mir = unsafe {
+ mem::transmute::<Mir, Mir<'tcx>>(mir)
+ };
+
+ pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
+
+ tcx.alloc_mir(mir)
+ })
+}
+
/// A pass to lift all the types and substitutions in a Mir
/// to the global tcx. Sadly, we don't have a "folder" that
/// can change 'tcx so we have to transmute afterwards.
tcx: TyCtxt<'a, 'tcx, 'tcx>
}
-fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- body_id: hir::BodyId)
- -> (Mir<'tcx>, MirSource) {
- let tcx = infcx.tcx.global_tcx();
-
- let item_id = tcx.hir.body_owner(body_id);
- let src = MirSource::from_node(tcx, item_id);
- let cx = Cx::new(infcx, src);
- if let MirSource::Fn(id) = src {
- // fetch the fully liberated fn signature (that is, all bound
- // types/lifetimes replaced)
- let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
-
- let ty = tcx.item_type(tcx.hir.local_def_id(id));
- let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
- (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
- } else {
- (ty.fn_abi(), None)
- };
-
- let body = tcx.hir.body(body_id);
- let explicit_arguments =
- body.arguments
- .iter()
- .enumerate()
- .map(|(index, arg)| {
- (fn_sig.inputs()[index], Some(&*arg.pat))
- });
-
- let arguments = implicit_argument.into_iter().chain(explicit_arguments);
- (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src)
- } else {
- (build::construct_const(cx, body_id), src)
- }
-}
-
impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
- self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
- let (mut mir, src) = build(&infcx, body_id);
-
- // Convert the Mir to global types.
- let tcx = infcx.tcx.global_tcx();
- let mut globalizer = GlobalizeMir {
- tcx: tcx,
- span: mir.span
- };
- globalizer.visit_mir(&mut mir);
- let mir = unsafe {
- mem::transmute::<Mir, Mir<'tcx>>(mir)
- };
-
- pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
-
- let mir = tcx.alloc_mir(mir);
- let def_id = tcx.hir.local_def_id(src.item_id());
- tcx.maps.mir.borrow_mut().insert(def_id, mir);
- });
+ self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id));
let body = self.tcx.hir.body(body_id);
self.visit_body(body);