mir: factor out the parts of MIR building which are not fn-specific.
This commit is contained in:
parent
bbc41aa9a6
commit
cde2f5f116
2 changed files with 156 additions and 180 deletions
|
|
@ -10,12 +10,13 @@
|
|||
|
||||
use hair::cx::Cx;
|
||||
use rustc::middle::region::{CodeExtent, CodeExtentData};
|
||||
use rustc::ty::{self, FnOutput, Ty};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::repr::*;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use rustc::hir;
|
||||
use rustc::hir::pat_util::pat_is_binding;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::keywords;
|
||||
|
|
@ -159,53 +160,31 @@ macro_rules! unpack {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
/// the main entry point for building MIR for a function
|
||||
|
||||
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
||||
span: Span,
|
||||
fn_id: ast::NodeId,
|
||||
body_id: ast::NodeId,
|
||||
implicit_arguments: Vec<Ty<'tcx>>,
|
||||
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
|
||||
return_ty: FnOutput<'tcx>,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
|
||||
pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a,'tcx>,
|
||||
fn_id: ast::NodeId,
|
||||
arguments: A,
|
||||
return_ty: ty::FnOutput<'tcx>,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> (Mir<'tcx>, ScopeAuxiliaryVec)
|
||||
where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
|
||||
{
|
||||
let tcx = hir.tcx();
|
||||
let cfg = CFG { basic_blocks: vec![] };
|
||||
let span = tcx.map.span(fn_id);
|
||||
let mut builder = Builder::new(hir, span);
|
||||
|
||||
let mut builder = Builder {
|
||||
hir: hir,
|
||||
cfg: cfg,
|
||||
fn_span: span,
|
||||
scopes: vec![],
|
||||
scope_datas: vec![],
|
||||
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
|
||||
loop_scopes: vec![],
|
||||
temp_decls: vec![],
|
||||
var_decls: vec![],
|
||||
var_indices: FnvHashMap(),
|
||||
unit_temp: None,
|
||||
cached_resume_block: None,
|
||||
cached_return_block: None
|
||||
};
|
||||
|
||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||
|
||||
let mut arg_decls = None; // assigned to `Some` in closures below
|
||||
let body_id = ast_block.id;
|
||||
let call_site_extent =
|
||||
tcx.region_maps.lookup_code_extent(
|
||||
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
|
||||
let _ = builder.in_scope(call_site_extent, START_BLOCK, |builder, call_site_scope_id| {
|
||||
let mut block = START_BLOCK;
|
||||
let arg_extent =
|
||||
tcx.region_maps.lookup_code_extent(
|
||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
|
||||
unpack!(block = builder.in_scope(arg_extent, block, |builder, arg_scope_id| {
|
||||
arg_decls = Some(unpack!(block = builder.args_and_body(block,
|
||||
return_ty,
|
||||
implicit_arguments,
|
||||
explicit_arguments,
|
||||
arg_scope_id,
|
||||
ast_block)));
|
||||
block.unit()
|
||||
let arg_extent =
|
||||
tcx.region_maps.lookup_code_extent(
|
||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
|
||||
let mut block = START_BLOCK;
|
||||
let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block,
|
||||
|builder, call_site_scope_id| {
|
||||
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block,
|
||||
|builder, arg_scope_id| {
|
||||
builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block)
|
||||
}));
|
||||
|
||||
let return_block = builder.return_block();
|
||||
|
|
@ -213,20 +192,19 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
|||
TerminatorKind::Goto { target: return_block });
|
||||
builder.cfg.terminate(return_block, call_site_scope_id, span,
|
||||
TerminatorKind::Return);
|
||||
return_block.unit()
|
||||
});
|
||||
return_block.and(arg_decls)
|
||||
}));
|
||||
assert_eq!(block, builder.return_block());
|
||||
|
||||
assert!(
|
||||
builder.cfg.basic_blocks
|
||||
.iter()
|
||||
.enumerate()
|
||||
.all(|(index, block)| {
|
||||
if block.terminator.is_none() {
|
||||
bug!("no terminator on block {:?} in fn {:?}",
|
||||
index, fn_id)
|
||||
}
|
||||
true
|
||||
}));
|
||||
match tcx.node_id_to_type(fn_id).sty {
|
||||
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
|
||||
// RustCall pseudo-ABI untuples the last argument.
|
||||
if let Some(arg_decl) = arg_decls.last_mut() {
|
||||
arg_decl.spread = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Gather the upvars of a closure, if any.
|
||||
let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
|
||||
|
|
@ -251,72 +229,98 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
|||
}).collect()
|
||||
});
|
||||
|
||||
(
|
||||
Mir {
|
||||
basic_blocks: builder.cfg.basic_blocks,
|
||||
scopes: builder.scope_datas,
|
||||
var_decls: builder.var_decls,
|
||||
arg_decls: arg_decls.take().expect("args never built?"),
|
||||
temp_decls: builder.temp_decls,
|
||||
upvar_decls: upvar_decls,
|
||||
return_ty: return_ty,
|
||||
span: span
|
||||
},
|
||||
builder.scope_auxiliary,
|
||||
)
|
||||
builder.finish(upvar_decls, arg_decls, return_ty)
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
fn args_and_body(&mut self,
|
||||
mut block: BasicBlock,
|
||||
return_ty: FnOutput<'tcx>,
|
||||
implicit_arguments: Vec<Ty<'tcx>>,
|
||||
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
|
||||
argument_scope_id: ScopeId,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> BlockAnd<Vec<ArgDecl<'tcx>>>
|
||||
fn new(hir: Cx<'a, 'tcx>, span: Span) -> Builder<'a, 'tcx> {
|
||||
let mut builder = Builder {
|
||||
hir: hir,
|
||||
cfg: CFG { basic_blocks: vec![] },
|
||||
fn_span: span,
|
||||
scopes: vec![],
|
||||
scope_datas: vec![],
|
||||
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
|
||||
loop_scopes: vec![],
|
||||
temp_decls: vec![],
|
||||
var_decls: vec![],
|
||||
var_indices: FnvHashMap(),
|
||||
unit_temp: None,
|
||||
cached_resume_block: None,
|
||||
cached_return_block: None
|
||||
};
|
||||
|
||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
fn finish(self,
|
||||
upvar_decls: Vec<UpvarDecl>,
|
||||
arg_decls: Vec<ArgDecl<'tcx>>,
|
||||
return_ty: ty::FnOutput<'tcx>)
|
||||
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
|
||||
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
||||
if block.terminator.is_none() {
|
||||
span_bug!(self.fn_span, "no terminator on block {:?}", index);
|
||||
}
|
||||
}
|
||||
|
||||
(Mir {
|
||||
basic_blocks: self.cfg.basic_blocks,
|
||||
scopes: self.scope_datas,
|
||||
var_decls: self.var_decls,
|
||||
arg_decls: arg_decls,
|
||||
temp_decls: self.temp_decls,
|
||||
upvar_decls: upvar_decls,
|
||||
return_ty: return_ty,
|
||||
span: self.fn_span
|
||||
}, self.scope_auxiliary)
|
||||
}
|
||||
|
||||
fn args_and_body<A>(&mut self,
|
||||
mut block: BasicBlock,
|
||||
return_ty: ty::FnOutput<'tcx>,
|
||||
arguments: A,
|
||||
argument_scope_id: ScopeId,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> BlockAnd<Vec<ArgDecl<'tcx>>>
|
||||
where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
|
||||
{
|
||||
// to start, translate the argument patterns and collect the argument types.
|
||||
let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
|
||||
let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
|
||||
let arg_decls =
|
||||
implicits
|
||||
.chain(explicits)
|
||||
.enumerate()
|
||||
.map(|(index, (ty, pattern))| {
|
||||
let lvalue = Lvalue::Arg(index as u32);
|
||||
if let Some(pattern) = pattern {
|
||||
let pattern = self.hir.irrefutable_pat(pattern);
|
||||
unpack!(block = self.lvalue_into_pattern(block,
|
||||
argument_scope_id,
|
||||
pattern,
|
||||
&lvalue));
|
||||
}
|
||||
let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
|
||||
let lvalue = Lvalue::Arg(index as u32);
|
||||
if let Some(pattern) = pattern {
|
||||
let pattern = self.hir.irrefutable_pat(pattern);
|
||||
unpack!(block = self.lvalue_into_pattern(block,
|
||||
argument_scope_id,
|
||||
pattern,
|
||||
&lvalue));
|
||||
}
|
||||
|
||||
// Make sure we drop (parts of) the argument even when not matched on.
|
||||
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
|
||||
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
|
||||
argument_extent, &lvalue, ty);
|
||||
// Make sure we drop (parts of) the argument even when not matched on.
|
||||
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
|
||||
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
|
||||
argument_extent, &lvalue, ty);
|
||||
|
||||
let mut name = keywords::Invalid.name();
|
||||
if let Some(pat) = pattern {
|
||||
if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
|
||||
if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
|
||||
name = ident.node.name;
|
||||
}
|
||||
let mut name = keywords::Invalid.name();
|
||||
if let Some(pat) = pattern {
|
||||
if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
|
||||
if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
|
||||
name = ident.node.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArgDecl {
|
||||
ty: ty,
|
||||
spread: false,
|
||||
debug_name: name
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
ArgDecl {
|
||||
ty: ty,
|
||||
spread: false,
|
||||
debug_name: name
|
||||
}
|
||||
}).collect();
|
||||
|
||||
// FIXME(#32959): temporary hack for the issue at hand
|
||||
let return_is_unit = if let FnOutput::FnConverging(t) = return_ty {
|
||||
let return_is_unit = if let ty::FnConverging(t) = return_ty {
|
||||
t.is_nil()
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -28,11 +28,9 @@ use rustc::mir::mir_map::MirMap;
|
|||
use rustc::infer;
|
||||
use rustc::traits::ProjectionMode;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc::util::nodemap::NodeMap;
|
||||
use rustc::hir;
|
||||
use rustc::hir::intravisit::{self, Visitor};
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
|
|
@ -58,6 +56,24 @@ struct BuildMir<'a, 'tcx: 'a> {
|
|||
map: &'a mut MirMap<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BuildMir<'a, 'tcx> {
|
||||
fn build<F>(&mut self, id: ast::NodeId, f: F)
|
||||
where F: for<'b> FnOnce(Cx<'b, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
|
||||
{
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||
let infcx = infer::new_infer_ctxt(self.tcx,
|
||||
&self.tcx.tables,
|
||||
Some(param_env),
|
||||
ProjectionMode::AnyFinal);
|
||||
|
||||
let (mir, scope_auxiliary) = f(Cx::new(&infcx));
|
||||
|
||||
pretty::dump_mir(self.tcx, "mir_map", &0, id, &mir, Some(&scope_auxiliary));
|
||||
|
||||
assert!(self.map.map.insert(id, mir).is_none())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
|
||||
fn visit_fn(&mut self,
|
||||
fk: intravisit::FnKind<'tcx>,
|
||||
|
|
@ -65,82 +81,38 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
|
|||
body: &'tcx hir::Block,
|
||||
span: Span,
|
||||
id: ast::NodeId) {
|
||||
let implicit_arg_tys = if let intravisit::FnKind::Closure(..) = fk {
|
||||
vec![closure_self_ty(&self.tcx, id, body.id)]
|
||||
} else {
|
||||
vec![]
|
||||
// fetch the fully liberated fn signature (that is, all bound
|
||||
// types/lifetimes replaced)
|
||||
let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) {
|
||||
Some(f) => f.clone(),
|
||||
None => {
|
||||
span_bug!(span, "no liberated fn sig for {:?}", id);
|
||||
}
|
||||
};
|
||||
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||
let infcx = infer::new_infer_ctxt(self.tcx,
|
||||
&self.tcx.tables,
|
||||
Some(param_env),
|
||||
ProjectionMode::AnyFinal);
|
||||
let implicit_argument = if let intravisit::FnKind::Closure(..) = fk {
|
||||
Some((closure_self_ty(&self.tcx, id, body.id), None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
|
||||
Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
|
||||
Err(ErrorReported) => {}
|
||||
}
|
||||
let explicit_arguments =
|
||||
decl.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
(fn_sig.inputs[index], Some(&*arg.pat))
|
||||
});
|
||||
|
||||
self.build(id, |cx| {
|
||||
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
|
||||
build::construct_fn(cx, id, arguments, fn_sig.output, body)
|
||||
});
|
||||
|
||||
intravisit::walk_fn(self, fk, decl, body, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
|
||||
implicit_arg_tys: Vec<Ty<'tcx>>,
|
||||
fn_id: ast::NodeId,
|
||||
span: Span,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
body: &'tcx hir::Block)
|
||||
-> Result<Mir<'tcx>, ErrorReported> {
|
||||
// fetch the fully liberated fn signature (that is, all bound
|
||||
// types/lifetimes replaced)
|
||||
let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
|
||||
Some(f) => f.clone(),
|
||||
None => {
|
||||
span_bug!(span, "no liberated fn sig for {:?}", fn_id);
|
||||
}
|
||||
};
|
||||
|
||||
let arguments =
|
||||
decl.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
(fn_sig.inputs[index], &*arg.pat)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (mut mir, scope_auxiliary) =
|
||||
build::construct(cx,
|
||||
span,
|
||||
fn_id,
|
||||
body.id,
|
||||
implicit_arg_tys,
|
||||
arguments,
|
||||
fn_sig.output,
|
||||
body);
|
||||
|
||||
match cx.tcx().node_id_to_type(fn_id).sty {
|
||||
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
|
||||
// RustCall pseudo-ABI untuples the last argument.
|
||||
if let Some(arg_decl) = mir.arg_decls.last_mut() {
|
||||
arg_decl.spread = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
pretty::dump_mir(cx.tcx(),
|
||||
"mir_map",
|
||||
&0,
|
||||
fn_id,
|
||||
&mir,
|
||||
Some(&scope_auxiliary));
|
||||
|
||||
Ok(mir)
|
||||
}
|
||||
|
||||
fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
closure_expr_id: ast::NodeId,
|
||||
body_id: ast::NodeId)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue