about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-08-14 21:16:16 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-08-17 15:21:58 -0400
commitf3990feb2e411d0826dfb83aa7078468da5d1907 (patch)
tree322e36b567dc89923a6f127940c314c1489ec82d
parent00e699faf3ec39715477b8386fba9deab2e2c925 (diff)
create a trait to ensure that data is tracked
Also write a comment explaining the system.
-rw-r--r--src/librustc_metadata/encoder.rs33
-rw-r--r--src/librustc_metadata/index_builder.rs106
2 files changed, 117 insertions, 22 deletions
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 309347a5e5a..494699af7ba 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 a971c618a21..c7ee3efaa81 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<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);
+    }
+}