]> git.lizzy.rs Git - rust.git/blob - src/librustc_metadata/index_builder.rs
Auto merge of #57770 - Zoxc:no-hash-query, r=michaelwoerister
[rust.git] / src / librustc_metadata / index_builder.rs
1 //! Builder types for generating the "item data" section of the
2 //! metadata. This section winds up looking like this:
3 //!
4 //! ```
5 //! <common::data> // big list of item-like things...
6 //!    <common::data_item> // ...for most def-ids, there is an entry.
7 //!    </common::data_item>
8 //! </common::data>
9 //! ```
10 //!
11 //! As we generate this listing, we collect the offset of each
12 //! `data_item` entry and store it in an index. Then, when we load the
13 //! metadata, we can skip right to the metadata for a particular item.
14 //!
15 //! In addition to the offset, we need to track the data that was used
16 //! to generate the contents of each `data_item`. This is so that we
17 //! can figure out which HIR nodes contributed to that data for
18 //! incremental compilation purposes.
19 //!
20 //! The `IndexBuilder` facilitates both of these. It is created
21 //! with an `EncodingContext` (`ecx`), which it encapsulates.
22 //! It has one main method, `record()`. You invoke `record`
23 //! like so to create a new `data_item` element in the list:
24 //!
25 //! ```
26 //! index.record(some_def_id, callback_fn, data)
27 //! ```
28 //!
29 //! What record will do is to (a) record the current offset, (b) emit
30 //! the `common::data_item` tag, and then call `callback_fn` with the
31 //! given data as well as the `EncodingContext`. Once `callback_fn`
32 //! returns, the `common::data_item` tag will be closed.
33 //!
34 //! `EncodingContext` does not offer the `record` method, so that we
35 //! can ensure that `common::data_item` elements are never nested.
36 //!
37 //! In addition, while the `callback_fn` is executing, we will push a
38 //! task `MetaData(some_def_id)`, which can then observe the
39 //! reads/writes that occur in the task. For this reason, the `data`
40 //! argument that is given to the `callback_fn` must implement the
41 //! trait `DepGraphRead`, which indicates how to register reads on the
42 //! data in this new task (note that many types of data, such as
43 //! `DefId`, do not currently require any reads to be registered,
44 //! since they are not derived from a HIR node). This is also why we
45 //! give a callback fn, rather than taking a closure: it allows us to
46 //! easily control precisely what data is given to that fn.
47
48 use crate::encoder::EncodeContext;
49 use crate::index::Index;
50 use crate::schema::*;
51 use crate::isolated_encoder::IsolatedEncoder;
52
53 use rustc::hir;
54 use rustc::hir::def_id::DefId;
55 use rustc::ty::TyCtxt;
56 use syntax::ast;
57
58 use std::ops::{Deref, DerefMut};
59
60 /// Builder that can encode new items, adding them into the index.
61 /// Item encoding cannot be nested.
62 pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> {
63     items: Index,
64     pub ecx: &'a mut EncodeContext<'b, 'tcx>,
65 }
66
67 impl<'a, 'b, 'tcx> Deref for IndexBuilder<'a, 'b, 'tcx> {
68     type Target = EncodeContext<'b, 'tcx>;
69     fn deref(&self) -> &Self::Target {
70         self.ecx
71     }
72 }
73
74 impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> {
75     fn deref_mut(&mut self) -> &mut Self::Target {
76         self.ecx
77     }
78 }
79
80 impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
81     pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self {
82         IndexBuilder {
83             items: Index::new(ecx.tcx.hir().definitions().def_index_counts_lo_hi()),
84             ecx,
85         }
86     }
87
88     /// Emit the data for a def-id to the metadata. The function to
89     /// emit the data is `op`, and it will be given `data` as
90     /// arguments. This `record` function will call `op` to generate
91     /// the `Entry` (which may point to other encoded information)
92     /// and will then record the `Lazy<Entry>` for use in the index.
93     ///
94     /// In addition, it will setup a dep-graph task to track what data
95     /// `op` accesses to generate the metadata, which is later used by
96     /// incremental compilation to compute a hash for the metadata and
97     /// track changes.
98     ///
99     /// The reason that `op` is a function pointer, and not a closure,
100     /// is that we want to be able to completely track all data it has
101     /// access to, so that we can be sure that `DATA: DepGraphRead`
102     /// holds, and that it is therefore not gaining "secret" access to
103     /// bits of HIR or other state that would not be trackd by the
104     /// content system.
105     pub fn record<'x, DATA>(&'x mut self,
106                             id: DefId,
107                             op: fn(&mut IsolatedEncoder<'x, 'b, 'tcx>, DATA) -> Entry<'tcx>,
108                             data: DATA)
109         where DATA: DepGraphRead
110     {
111         assert!(id.is_local());
112
113         // We don't track this since we are explicitly computing the incr. comp.
114         // hashes anyway. In theory we could do some tracking here and use it to
115         // avoid rehashing things (and instead cache the hashes) but it's
116         // unclear whether that would be a win since hashing is cheap enough.
117         self.ecx.tcx.dep_graph.with_ignore(move || {
118             let mut entry_builder = IsolatedEncoder::new(self.ecx);
119             let entry = op(&mut entry_builder, data);
120             let entry = entry_builder.lazy(&entry);
121
122             self.items.record(id, entry);
123         })
124     }
125
126     pub fn into_items(self) -> Index {
127         self.items
128     }
129 }
130
131 /// Trait used for data that can be passed from outside a dep-graph
132 /// task.  The data must either be of some safe type, such as a
133 /// `DefId` index, or implement the `read` method so that it can add
134 /// a read of whatever dep-graph nodes are appropriate.
135 pub trait DepGraphRead {
136     fn read(&self, tcx: TyCtxt<'_, '_, '_>);
137 }
138
139 impl DepGraphRead for DefId {
140     fn read(&self, _tcx: TyCtxt<'_, '_, '_>) {}
141 }
142
143 impl DepGraphRead for ast::NodeId {
144     fn read(&self, _tcx: TyCtxt<'_, '_, '_>) {}
145 }
146
147 impl<T> DepGraphRead for Option<T>
148     where T: DepGraphRead
149 {
150     fn read(&self, tcx: TyCtxt<'_, '_, '_>) {
151         match *self {
152             Some(ref v) => v.read(tcx),
153             None => (),
154         }
155     }
156 }
157
158 impl<T> DepGraphRead for [T]
159     where T: DepGraphRead
160 {
161     fn read(&self, tcx: TyCtxt<'_, '_, '_>) {
162         for i in self {
163             i.read(tcx);
164         }
165     }
166 }
167
168 macro_rules! read_tuple {
169     ($($name:ident),*) => {
170         impl<$($name),*> DepGraphRead for ($($name),*)
171             where $($name: DepGraphRead),*
172         {
173             #[allow(non_snake_case)]
174             fn read(&self, tcx: TyCtxt<'_, '_, '_>) {
175                 let &($(ref $name),*) = self;
176                 $($name.read(tcx);)*
177             }
178         }
179     }
180 }
181 read_tuple!(A, B);
182 read_tuple!(A, B, C);
183
184 macro_rules! read_hir {
185     ($t:ty) => {
186         impl<'tcx> DepGraphRead for &'tcx $t {
187             fn read(&self, tcx: TyCtxt<'_, '_, '_>) {
188                 tcx.hir().read(self.id);
189             }
190         }
191     }
192 }
193 read_hir!(hir::Item);
194 read_hir!(hir::ImplItem);
195 read_hir!(hir::TraitItem);
196 read_hir!(hir::ForeignItem);
197 read_hir!(hir::MacroDef);
198
199 /// Leaks access to a value of type T without any tracking. This is
200 /// suitable for ambiguous types like `usize`, which *could* represent
201 /// tracked data (e.g., if you read it out of a HIR node) or might not
202 /// (e.g., if it's an index). Adding in an `Untracked` is an
203 /// assertion, essentially, that the data does not need to be tracked
204 /// (or that read edges will be added by some other way).
205 ///
206 /// A good idea is to add to each use of `Untracked` an explanation of
207 /// why this value is ok.
208 pub struct Untracked<T>(pub T);
209
210 impl<T> DepGraphRead for Untracked<T> {
211     fn read(&self, _tcx: TyCtxt<'_, '_, '_>) {}
212 }
213
214 /// Newtype that can be used to package up misc data extracted from a
215 /// HIR node that doesn't carry its own id. This will allow an
216 /// arbitrary `T` to be passed in, but register a read on the given
217 /// node-id.
218 pub struct FromId<T>(pub ast::NodeId, pub T);
219
220 impl<T> DepGraphRead for FromId<T> {
221     fn read(&self, tcx: TyCtxt<'_, '_, '_>) {
222         tcx.hir().read(self.0);
223     }
224 }