rustc_mir: expose MIR building through ty::maps::Provider.

This commit is contained in:
Eduard-Mihai Burtescu 2017-02-08 11:16:14 +02:00
parent b5c4244c6c
commit 374ea14412
2 changed files with 104 additions and 59 deletions

View File

@ -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,

View File

@ -17,6 +17,7 @@
//! - `#[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;
@ -24,9 +25,9 @@ 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};
@ -34,6 +35,7 @@ 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>) {
@ -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.
@ -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);