create a trait to ensure that data is tracked

Also write a comment explaining the system.
This commit is contained in:
Niko Matsakis 2016-08-14 21:16:16 -04:00
parent 00e699faf3
commit f3990feb2e
2 changed files with 117 additions and 22 deletions

View File

@ -53,7 +53,7 @@ use rustc::hir::intravisit::Visitor;
use rustc::hir::intravisit;
use rustc::hir::map::DefKey;
use super::index_builder::{IndexBuilder, ItemContentBuilder, XRef};
use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, XRef};
pub struct EncodeContext<'a, 'tcx: 'a> {
pub diag: &'a Handler,
@ -198,8 +198,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
fn encode_enum_variant_infos(&mut self,
enum_did: DefId,
vis: &hir::Visibility) {
enum_did: DefId) {
debug!("encode_enum_variant_info(enum_did={:?})", enum_did);
let ecx = self.ecx();
let def = ecx.tcx.lookup_adt_def(enum_did);
@ -207,15 +206,15 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
for (i, variant) in def.variants.iter().enumerate() {
self.record(variant.did,
ItemContentBuilder::encode_enum_variant_info,
(enum_did, i, vis));
(enum_did, i));
}
}
}
impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
fn encode_enum_variant_info(&mut self,
(enum_did, index, vis):
(DefId, usize, &hir::Visibility)) {
(enum_did, index):
(DefId, usize)) {
let ecx = self.ecx;
let def = ecx.tcx.lookup_adt_def(enum_did);
let variant = &def.variants[index];
@ -229,7 +228,10 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
});
encode_name(self.rbml_w, variant.name);
self.encode_parent_item(enum_did);
self.encode_visibility(vis);
let enum_id = ecx.tcx.map.as_local_node_id(enum_did).unwrap();
let enum_vis = &ecx.tcx.map.expect_item(enum_id).vis;
self.encode_visibility(enum_vis);
let attrs = ecx.tcx.get_attrs(vid);
encode_attributes(self.rbml_w, &attrs);
@ -294,8 +296,8 @@ fn encode_reexports(ecx: &EncodeContext,
impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
fn encode_info_for_mod(&mut self,
(md, attrs, id, name, vis):
(&hir::Mod, &[ast::Attribute], NodeId, Name, &hir::Visibility)) {
FromId(id, (md, attrs, name, vis)):
FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) {
let ecx = self.ecx();
encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id));
@ -936,7 +938,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
self.encode_method_argument_names(&decl);
}
hir::ItemMod(ref m) => {
self.encode_info_for_mod((m, &item.attrs, item.id, item.name, &item.vis));
self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis)));
}
hir::ItemForeignMod(ref fm) => {
encode_def_id_and_key(ecx, self.rbml_w, def_id);
@ -1166,7 +1168,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
// no sub-item recording needed in these cases
}
hir::ItemEnum(..) => {
self.encode_enum_variant_infos(def_id, &item.vis);
self.encode_enum_variant_infos(def_id);
}
hir::ItemStruct(ref struct_def, _) => {
self.encode_addl_struct_info(def_id, struct_def.id(), item);
@ -1395,11 +1397,10 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
let mut index = IndexBuilder::new(ecx, rbml_w);
index.record(DefId::local(CRATE_DEF_INDEX),
ItemContentBuilder::encode_info_for_mod,
(&krate.module,
&[],
CRATE_NODE_ID,
syntax::parse::token::intern(&ecx.link_meta.crate_name),
&hir::Public));
FromId(CRATE_NODE_ID, (&krate.module,
&[],
syntax::parse::token::intern(&ecx.link_meta.crate_name),
&hir::Public)));
krate.visit_all_items(&mut EncodeVisitor {
index: &mut index,
});

View File

@ -13,9 +13,11 @@ use encoder::EncodeContext;
use index::IndexData;
use rbml::writer::Encoder;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use syntax::ast;
use std::ops::{Deref, DerefMut};
/// Builder that can encode new items, adding them into the index.
@ -51,21 +53,34 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
}
}
/// Records that `id` is being emitted at the current offset.
/// This data is later used to construct the item index in the
/// metadata so we can quickly find the data for a given item.
/// Emit the data for a def-id to the metadata. The function to
/// emit the data is `op`, and it will be given `data` as
/// arguments. This `record` function will start/end an RBML tag
/// and record the current offset for use in the index, calling
/// `op` to generate the data in the RBML tag.
///
/// Returns a dep-graph task that you should keep live as long as
/// the data for this item is being emitted.
/// In addition, it will setup a dep-graph task to track what data
/// `op` accesses to generate the metadata, which is later used by
/// incremental compilation to compute a hash for the metadata and
/// track changes.
///
/// The reason that `op` is a function pointer, and not a closure,
/// is that we want to be able to completely track all data it has
/// access to, so that we can be sure that `DATA: DepGraphRead`
/// holds, and that it is therefore not gaining "secret" access to
/// bits of HIR or other state that would not be trackd by the
/// content system.
pub fn record<DATA>(&mut self,
id: DefId,
op: fn(&mut ItemContentBuilder<'a, 'tcx, 'encoder>, DATA),
data: DATA)
where DATA: DepGraphRead
{
let position = self.rbml_w.mark_stable_position();
self.items.record(id, position);
let _task = self.ecx.tcx.dep_graph.in_task(DepNode::MetaData(id));
self.rbml_w.start_tag(tag_items_data_item).unwrap();
data.read(self.ecx.tcx);
op(self, data);
self.rbml_w.end_tag().unwrap();
}
@ -100,3 +115,82 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
}
}
/// Trait that registers reads for types that are tracked in the
/// dep-graph. Mostly it is implemented for indices like DefId etc
/// which do not need to register a read.
pub trait DepGraphRead {
fn read(&self, tcx: TyCtxt);
}
impl DepGraphRead for usize {
fn read(&self, _tcx: TyCtxt) { }
}
impl DepGraphRead for DefId {
fn read(&self, _tcx: TyCtxt) { }
}
impl DepGraphRead for ast::NodeId {
fn read(&self, _tcx: TyCtxt) { }
}
impl<T> DepGraphRead for Option<T>
where T: DepGraphRead
{
fn read(&self, tcx: TyCtxt) {
match *self {
Some(ref v) => v.read(tcx),
None => (),
}
}
}
impl<T> DepGraphRead for [T]
where T: DepGraphRead
{
fn read(&self, tcx: TyCtxt) {
for i in self {
i.read(tcx);
}
}
}
macro_rules! read_tuple {
($($name:ident),*) => {
impl<$($name),*> DepGraphRead for ($($name),*)
where $($name: DepGraphRead),*
{
#[allow(non_snake_case)]
fn read(&self, tcx: TyCtxt) {
let &($(ref $name),*) = self;
$($name.read(tcx);)*
}
}
}
}
read_tuple!(A,B);
read_tuple!(A,B,C);
macro_rules! read_hir {
($t:ty) => {
impl<'tcx> DepGraphRead for &'tcx $t {
fn read(&self, tcx: TyCtxt) {
tcx.map.read(self.id);
}
}
}
}
read_hir!(hir::Item);
read_hir!(hir::ImplItem);
read_hir!(hir::TraitItem);
read_hir!(hir::ForeignItem);
/// You can use `FromId(X, ...)` to indicate that `...` came from node
/// `X`; so we will add a read from the suitable `Hir` node.
pub struct FromId<T>(pub ast::NodeId, pub T);
impl<T> DepGraphRead for FromId<T> {
fn read(&self, tcx: TyCtxt) {
tcx.map.read(self.0);
}
}