rustc_mir: expose MIR building through ty::maps::Provider.
This commit is contained in:
parent
b5c4244c6c
commit
374ea14412
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user