diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 11a1aab7b5b9..7f7b87fb880b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -415,7 +415,7 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { fn encode_fields(&mut self, adt_def_id: DefId) { - let def = self.ecx.tcx.lookup_adt_def(adt_def_id); + let def = self.ecx().tcx.lookup_adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, @@ -1155,7 +1155,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { /// normally in the visitor walk. fn encode_addl_info_for_item(&mut self, item: &hir::Item) { - let def_id = self.ecx.tcx.map.local_def_id(item.id); + let def_id = self.ecx().tcx.map.local_def_id(item.id); match item.node { hir::ItemStatic(..) | hir::ItemConst(..) | @@ -1187,7 +1187,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, struct_node_id: ast::NodeId, item: &hir::Item) { - let ecx = self.ecx; + let ecx = self.ecx(); let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); @@ -1213,7 +1213,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, impl_id: ast::NodeId, ast_items: &[hir::ImplItem]) { - let ecx = self.ecx; + let ecx = self.ecx(); let impl_items = ecx.tcx.impl_items.borrow(); let items = &impl_items[&def_id]; @@ -1240,7 +1240,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, trait_items: &[hir::TraitItem]) { // Now output the trait item info for each trait item. - let tcx = self.ecx.tcx; + let tcx = self.ecx().tcx; let r = tcx.trait_item_def_ids(def_id); for (item_def_id, trait_item) in r.iter().zip(trait_items) { let item_def_id = item_def_id.def_id(); @@ -1311,7 +1311,7 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_item(&mut self, item: &'tcx hir::Item) { intravisit::walk_item(self, item); - let def_id = self.index.ecx.tcx.map.local_def_id(item.id); + let def_id = self.index.ecx().tcx.map.local_def_id(item.id); match item.node { hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these _ => self.index.record(def_id, @@ -1322,7 +1322,7 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - let def_id = self.index.ecx.tcx.map.local_def_id(ni.id); + let def_id = self.index.ecx().tcx.map.local_def_id(ni.id); self.index.record(def_id, ItemContentBuilder::encode_info_for_foreign_item, (def_id, ni)); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index c7ee3efaa81d..37f29696808e 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -8,6 +8,60 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Builder types for generating the "item data" section of the +//! metadata. This section winds up looking like this: +//! +//! ``` +//! // big list of item-like things... +//! // ...for most def-ids, there is an entry. +//! +//! +//! ``` +//! +//! As we generate this listing, we collect the offset of each +//! `data_item` entry and store it in an index. Then, when we load the +//! metadata, we can skip right to the metadata for a particular item. +//! +//! In addition to the offset, we need to track the data that was used +//! to generate the contents of each `data_item`. This is so that we +//! can figure out which HIR nodes contributors to that data for +//! incremental compilation purposes. +//! +//! The `IndexBuilder` facilitates with both of these. It is created +//! with an RBML encoder isntance (`rbml_w`) along with an +//! `EncodingContext` (`ecx`), which it encapsulates. It has one main +//! method, `record()`. You invoke `record` like so to create a new +//! `data_item` element in the list: +//! +//! ``` +//! index.record(some_def_id, callback_fn, data) +//! ``` +//! +//! What record will do is to (a) record the current offset, (b) emit +//! the `common::data_item` tag, and then call `callback_fn` with the +//! given data as well as an `ItemContentBuilder`. Once `callback_fn` +//! returns, the `common::data_item` tag will be closed. +//! +//! The `ItemContentBuilder` is another type that just offers access +//! to the `ecx` and `rbml_w` that were given in, as well as +//! maintaining a list of `xref` instances, which are used to extract +//! common data so it is not re-serialized. +//! +//! `ItemContentBuilder` is a distinct type which does not offer the +//! `record` method, so that we can ensure that `common::data_item` elements +//! are never nested. +//! +//! In addition, while the `callback_fn` is executing, we will push a +//! task `MetaData(some_def_id)`, which can then observe the +//! reads/writes that occur in the task. For this reason, the `data` +//! argument that is given to the `callback_fn` must implement the +//! trait `DepGraphRead`, which indicates how to register reads on the +//! data in this new task (note that many types of data, such as +//! `DefId`, do not currently require any reads to be registered, +//! since they are not derived from a HIR node). This is also why we +//! give a callback fn, rather than taking a closure: it allows us to +//! easily control precisely what data is given to that fn. + use common::tag_items_data_item; use encoder::EncodeContext; use index::IndexData; @@ -18,7 +72,6 @@ use rustc::hir::def_id::DefId; 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. /// Item encoding cannot be nested. @@ -53,6 +106,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } + pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { + self.builder.ecx() + } + /// 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 @@ -76,13 +133,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { data: DATA) where DATA: DepGraphRead { - let position = self.rbml_w.mark_stable_position(); + let position = self.builder.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(); + let _task = self.ecx().tcx.dep_graph.in_task(DepNode::MetaData(id)); + self.builder.rbml_w.start_tag(tag_items_data_item).unwrap(); + data.read(self.ecx().tcx); + op(&mut self.builder, data); + self.builder.rbml_w.end_tag().unwrap(); } pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { @@ -90,20 +147,6 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> Deref for IndexBuilder<'a, 'tcx, 'encoder> { - type Target = ItemContentBuilder<'a, 'tcx, 'encoder>; - - fn deref(&self) -> &Self::Target { - &self.builder - } -} - -impl<'a, 'tcx, 'encoder> DerefMut for IndexBuilder<'a, 'tcx, 'encoder> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.builder - } -} - impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { self.ecx @@ -115,9 +158,10 @@ 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. +/// Trait used for data that can be passed from outside a dep-graph +/// task. The data must either be of some safe type, such as a +/// `DefId` index, or implement the `read` method so that it can add +/// a read of whatever dep-graph nodes are appropriate. pub trait DepGraphRead { fn read(&self, tcx: TyCtxt); } @@ -185,8 +229,10 @@ 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. +/// Newtype that can be used to package up misc data extracted from a +/// HIR node that doesn't carry its own id. This will allow an +/// arbitrary `T` to be passed in, but register a read on the given +/// node-id. pub struct FromId(pub ast::NodeId, pub T); impl DepGraphRead for FromId {