Auto merge of #38813 - eddyb:lazy-11, r=nikomatsakis

[11/n] Separate ty::Tables into one per each body.

_This is part of a series ([prev](https://github.com/rust-lang/rust/pull/38449) | [next]()) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._

<hr>

In order to track the results of type-checking and inference for incremental recompilation, they must be stored separately for each function or constant value, instead of lumped together.

These side-`Tables` also have to be tracked by various passes, as they visit through bodies (all of which have `Tables`, even if closures share the ones from their parent functions). This is usually done by switching a `tables` field in an override of `visit_nested_body` before recursing through `visit_body`, to the relevant one and then restoring it - however, in many cases the nesting is unnecessary and creating the visitor for each body in the crate and then visiting that body, would be a much cleaner solution.

To simplify handling of inlined HIR & its side-tables, their `NodeId` remapping and entries HIR map were fully stripped out, which means that `NodeId`s from inlined HIR must not be used where a local `NodeId` is expected. It might be possible to make the nodes (`Expr`, `Block`, `Pat`, etc.) that only show up within a `Body` have IDs that are scoped to that `Body`, which would also allow `Tables` to use `Vec`s.

That last part also fixes #38790 which was accidentally introduced in a previous refactor.
This commit is contained in:
bors 2017-01-08 11:36:52 +00:00
commit cbf88730e7
76 changed files with 1128 additions and 1415 deletions

View file

@ -99,7 +99,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
}
}
fn nest<F>(&mut self, scope_id: NodeId, f: F)
fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
{
let parent_scope = self.cur_scope;
@ -108,6 +108,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
self.cur_scope = parent_scope;
}
fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
{
let old_tables = self.save_ctxt.tables;
let item_def_id = self.tcx.map.local_def_id(item_id);
self.save_ctxt.tables = self.tcx.item_tables(item_def_id);
f(self);
self.save_ctxt.tables = old_tables;
}
pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
let source_file = self.tcx.sess.local_crate_source_file.as_ref();
let crate_root = source_file.map(|source_file| {
@ -337,7 +347,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
collector.visit_pat(&arg.pat);
let span_utils = self.span.clone();
for &(id, ref p, ..) in &collector.collected_paths {
let typ = match self.tcx.tables().node_types.get(&id) {
let typ = match self.save_ctxt.tables.node_types.get(&id) {
Some(s) => s.to_string(),
None => continue,
};
@ -378,7 +388,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
let sig_str = ::make_signature(&sig.decl, &sig.generics);
if body.is_some() {
self.process_formals(&sig.decl.inputs, &method_data.qualname);
self.nest_tables(id, |v| {
v.process_formals(&sig.decl.inputs, &method_data.qualname)
});
}
// If the method is defined in an impl, then try and find the corresponding
@ -448,7 +460,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
// walk the fn body
if let Some(body) = body {
self.nest(id, |v| v.visit_block(body));
self.nest_tables(id, |v| v.nest_scope(id, |v| v.visit_block(body)));
}
}
@ -520,7 +532,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
self.dumper.function(fn_data.clone().lower(self.tcx));
}
self.process_formals(&decl.inputs, &fn_data.qualname);
self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, &fn_data.qualname));
self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
}
@ -532,7 +544,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
self.visit_ty(&ret_ty);
}
self.nest(item.id, |v| v.visit_block(&body));
self.nest_tables(item.id, |v| v.nest_scope(item.id, |v| v.visit_block(&body)));
}
fn process_static_or_const_item(&mut self,
@ -991,7 +1003,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
match p.node {
PatKind::Struct(ref path, ref fields, _) => {
visit::walk_path(self, path);
let adt = match self.tcx.tables().node_id_to_type_opt(p.id) {
let adt = match self.save_ctxt.tables.node_id_to_type_opt(p.id) {
Some(ty) => ty.ty_adt_def().unwrap(),
None => {
visit::walk_pat(self, p);
@ -1032,7 +1044,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
ast::Mutability::Immutable => value.to_string(),
_ => String::new(),
};
let typ = match self.tcx.tables().node_types.get(&id) {
let typ = match self.save_ctxt.tables.node_types.get(&id) {
Some(typ) => {
let typ = typ.to_string();
if !value.is_empty() {
@ -1286,7 +1298,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
self.process_trait(item, generics, trait_refs, methods),
Mod(ref m) => {
self.process_mod(item);
self.nest(item.id, |v| visit::walk_mod(v, m));
self.nest_scope(item.id, |v| visit::walk_mod(v, m));
}
Ty(ref ty, ref ty_params) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
@ -1349,6 +1361,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
visit::walk_path(self, path);
}
ast::TyKind::Array(ref element, ref length) => {
self.visit_ty(element);
self.nest_tables(length.id, |v| v.visit_expr(length));
}
_ => visit::walk_ty(self, t),
}
}
@ -1367,7 +1383,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
}
ast::ExprKind::Struct(ref path, ref fields, ref base) => {
let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
let adt = match self.tcx.tables().expr_ty_opt(&hir_expr) {
let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
Some(ty) => ty.ty_adt_def().unwrap(),
None => {
visit::walk_expr(self, ex);
@ -1399,7 +1415,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
return;
}
};
let ty = match self.tcx.tables().expr_ty_adjusted_opt(&hir_node) {
let ty = match self.save_ctxt.tables.expr_ty_adjusted_opt(&hir_node) {
Some(ty) => &ty.sty,
None => {
visit::walk_expr(self, ex);
@ -1427,7 +1443,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
ast::ExprKind::Closure(_, ref decl, ref body, _fn_decl_span) => {
let mut id = String::from("$");
id.push_str(&ex.id.to_string());
self.process_formals(&decl.inputs, &id);
// walk arg and return types
for arg in &decl.inputs {
@ -1439,7 +1454,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
}
// walk the body
self.nest(ex.id, |v| v.visit_expr(body));
self.nest_tables(ex.id, |v| {
v.process_formals(&decl.inputs, &id);
v.nest_scope(ex.id, |v| v.visit_expr(body))
});
}
ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
@ -1455,6 +1473,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
visit::walk_block(self, block);
opt_else.as_ref().map(|el| visit::walk_expr(self, el));
}
ast::ExprKind::Repeat(ref element, ref count) => {
self.visit_expr(element);
self.nest_tables(count.id, |v| v.visit_expr(count));
}
_ => {
visit::walk_expr(self, ex)
}
@ -1492,7 +1514,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
} else {
"<mutable>".to_string()
};
let typ = self.tcx.tables().node_types
let typ = self.save_ctxt.tables.node_types
.get(&id).map(|t| t.to_string()).unwrap_or(String::new());
value.push_str(": ");
value.push_str(&typ);

View file

@ -84,6 +84,7 @@ pub mod recorder {
pub struct SaveContext<'l, 'tcx: 'l> {
tcx: TyCtxt<'l, 'tcx, 'tcx>,
tables: &'l ty::Tables<'tcx>,
analysis: &'l ty::CrateAnalysis<'tcx>,
span_utils: SpanUtils<'tcx>,
}
@ -93,24 +94,6 @@ macro_rules! option_try(
);
impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
pub fn new(tcx: TyCtxt<'l, 'tcx, 'tcx>,
analysis: &'l ty::CrateAnalysis<'tcx>)
-> SaveContext<'l, 'tcx> {
let span_utils = SpanUtils::new(&tcx.sess);
SaveContext::from_span_utils(tcx, analysis, span_utils)
}
pub fn from_span_utils(tcx: TyCtxt<'l, 'tcx, 'tcx>,
analysis: &'l ty::CrateAnalysis<'tcx>,
span_utils: SpanUtils<'tcx>)
-> SaveContext<'l, 'tcx> {
SaveContext {
tcx: tcx,
analysis: analysis,
span_utils: span_utils,
}
}
// List external crates used by the current crate.
pub fn get_external_crates(&self) -> Vec<CrateData> {
let mut result = Vec::new();
@ -460,7 +443,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
let hir_node = self.tcx.map.expect_expr(expr.id);
let ty = self.tcx.tables().expr_ty_adjusted_opt(&hir_node);
let ty = self.tables.expr_ty_adjusted_opt(&hir_node);
if ty.is_none() || ty.unwrap().sty == ty::TyError {
return None;
}
@ -474,7 +457,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
return None;
}
};
match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
match self.tables.expr_ty_adjusted(&hir_node).sty {
ty::TyAdt(def, _) if !def.is_enum() => {
let f = def.struct_variant().field_named(ident.node.name);
let sub_span = self.span_utils.span_for_last_ident(expr.span);
@ -493,7 +476,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
}
ast::ExprKind::Struct(ref path, ..) => {
match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
match self.tables.expr_ty_adjusted(&hir_node).sty {
ty::TyAdt(def, _) if !def.is_enum() => {
let sub_span = self.span_utils.span_for_last_ident(path.span);
filter!(self.span_utils, sub_span, path.span, None);
@ -514,7 +497,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
ast::ExprKind::MethodCall(..) => {
let method_call = ty::MethodCall::expr(expr.id);
let method_id = self.tcx.tables().method_map[&method_call].def_id;
let method_id = self.tables.method_map[&method_call].def_id;
let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
ty::ImplContainer(_) => (Some(method_id), None),
ty::TraitContainer(_) => (None, Some(method_id)),
@ -551,7 +534,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Node::NodePat(&hir::Pat { node: hir::PatKind::Path(ref qpath), .. }) |
Node::NodePat(&hir::Pat { node: hir::PatKind::Struct(ref qpath, ..), .. }) |
Node::NodePat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. }) => {
self.tcx.tables().qpath_def(qpath, id)
self.tables.qpath_def(qpath, id)
}
Node::NodeLocal(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => {
@ -914,7 +897,12 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
root_path.pop();
let output = &mut output_file;
let save_ctxt = SaveContext::new(tcx, analysis);
let save_ctxt = SaveContext {
tcx: tcx,
tables: &ty::Tables::empty(),
analysis: analysis,
span_utils: SpanUtils::new(&tcx.sess),
};
macro_rules! dump {
($new_dumper: expr) => {{