Skip to content

Commit

Permalink
rustc_mir: expose MIR building through ty::maps::Provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Feb 25, 2017
1 parent b5c4244 commit 374ea14
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 59 deletions.
5 changes: 3 additions & 2 deletions src/librustc_driver/driver.rs
Expand Up @@ -872,9 +872,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,

let index = stability::Index::new(&hir_map);

let local_providers = ty::maps::Providers::default();
let mut extern_providers = ty::maps::Providers::default();
let mut local_providers = ty::maps::Providers::default();
mir::mir_map::provide(&mut local_providers);

let mut extern_providers = ty::maps::Providers::default();
cstore::provide(&mut extern_providers);

TyCtxt::create_and_enter(sess,
Expand Down
158 changes: 101 additions & 57 deletions src/librustc_mir/mir_map.rs
Expand Up @@ -17,23 +17,25 @@
//! - `#[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 rustc::mir::visit::MutVisitor;
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::abi::Abi;
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>) {
Expand All @@ -42,6 +44,103 @@ 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.
Expand Down Expand Up @@ -79,68 +178,13 @@ struct BuildMir<'a, 'tcx: 'a> {
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);
Expand Down

0 comments on commit 374ea14

Please sign in to comment.