From f3990feb2e411d0826dfb83aa7078468da5d1907 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Aug 2016 21:16:16 -0400 Subject: [PATCH] create a trait to ensure that data is tracked Also write a comment explaining the system. --- src/librustc_metadata/encoder.rs | 33 ++++---- src/librustc_metadata/index_builder.rs | 106 +++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 22 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 309347a5e5a7..494699af7ba1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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, }); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index a971c618a212..c7ee3efaa81d 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -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(&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 DepGraphRead for Option + where T: DepGraphRead +{ + fn read(&self, tcx: TyCtxt) { + match *self { + Some(ref v) => v.read(tcx), + None => (), + } + } +} + +impl 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(pub ast::NodeId, pub T); + +impl DepGraphRead for FromId { + fn read(&self, tcx: TyCtxt) { + tcx.map.read(self.0); + } +}