]> git.lizzy.rs Git - rust.git/blob - src/librustc_hir/definitions.rs
79b70682739326b1ea18c4254e7cbc83fbade8d1
[rust.git] / src / librustc_hir / definitions.rs
1 //! For each definition, we track the following data. A definition
2 //! here is defined somewhat circularly as "something with a `DefId`",
3 //! but it generally corresponds to things like structs, enums, etc.
4 //! There are also some rather random cases (like const initializer
5 //! expressions) that are mostly just leftovers.
6
7 pub use crate::def_id::DefPathHash;
8 use crate::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
9 use crate::hir;
10
11 use rustc_ast::crate_disambiguator::CrateDisambiguator;
12 use rustc_data_structures::fx::FxHashMap;
13 use rustc_data_structures::stable_hasher::StableHasher;
14 use rustc_index::vec::IndexVec;
15 use rustc_span::hygiene::ExpnId;
16 use rustc_span::symbol::{sym, Symbol};
17
18 use log::debug;
19 use std::fmt::Write;
20 use std::hash::Hash;
21
22 /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
23 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
24 /// stores the `DefIndex` of its parent.
25 /// There is one `DefPathTable` for each crate.
26 #[derive(Clone, Default, RustcDecodable, RustcEncodable)]
27 pub struct DefPathTable {
28     index_to_key: IndexVec<DefIndex, DefKey>,
29     def_path_hashes: IndexVec<DefIndex, DefPathHash>,
30 }
31
32 impl DefPathTable {
33     fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
34         let index = {
35             let index = DefIndex::from(self.index_to_key.len());
36             debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
37             self.index_to_key.push(key);
38             index
39         };
40         self.def_path_hashes.push(def_path_hash);
41         debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
42         index
43     }
44
45     pub fn next_id(&self) -> DefIndex {
46         DefIndex::from(self.index_to_key.len())
47     }
48
49     #[inline(always)]
50     pub fn def_key(&self, index: DefIndex) -> DefKey {
51         self.index_to_key[index]
52     }
53
54     #[inline(always)]
55     pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
56         let hash = self.def_path_hashes[index];
57         debug!("def_path_hash({:?}) = {:?}", index, hash);
58         hash
59     }
60
61     pub fn add_def_path_hashes_to(&self, cnum: CrateNum, out: &mut FxHashMap<DefPathHash, DefId>) {
62         out.extend(self.def_path_hashes.iter().enumerate().map(|(index, &hash)| {
63             let def_id = DefId { krate: cnum, index: DefIndex::from(index) };
64             (hash, def_id)
65         }));
66     }
67
68     pub fn size(&self) -> usize {
69         self.index_to_key.len()
70     }
71 }
72
73 /// The definition table containing node definitions.
74 /// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
75 /// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
76 #[derive(Clone)]
77 pub struct Definitions {
78     table: DefPathTable,
79
80     // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
81     pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
82     /// The reverse mapping of `def_id_to_hir_id`.
83     pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
84
85     /// If `ExpnId` is an ID of some macro expansion,
86     /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
87     parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
88     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
89     expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
90 }
91
92 /// A unique identifier that we can use to lookup a definition
93 /// precisely. It combines the index of the definition's parent (if
94 /// any) with a `DisambiguatedDefPathData`.
95 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
96 pub struct DefKey {
97     /// The parent path.
98     pub parent: Option<DefIndex>,
99
100     /// The identifier of this node.
101     pub disambiguated_data: DisambiguatedDefPathData,
102 }
103
104 impl DefKey {
105     fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
106         let mut hasher = StableHasher::new();
107
108         // We hash a `0u8` here to disambiguate between regular `DefPath` hashes,
109         // and the special "root_parent" below.
110         0u8.hash(&mut hasher);
111         parent_hash.hash(&mut hasher);
112
113         let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
114
115         ::std::mem::discriminant(data).hash(&mut hasher);
116         if let Some(name) = data.get_opt_name() {
117             // Get a stable hash by considering the symbol chars rather than
118             // the symbol index.
119             name.as_str().hash(&mut hasher);
120         }
121
122         disambiguator.hash(&mut hasher);
123
124         DefPathHash(hasher.finish())
125     }
126
127     fn root_parent_stable_hash(
128         crate_name: &str,
129         crate_disambiguator: CrateDisambiguator,
130     ) -> DefPathHash {
131         let mut hasher = StableHasher::new();
132         // Disambiguate this from a regular `DefPath` hash; see `compute_stable_hash()` above.
133         1u8.hash(&mut hasher);
134         crate_name.hash(&mut hasher);
135         crate_disambiguator.hash(&mut hasher);
136         DefPathHash(hasher.finish())
137     }
138 }
139
140 /// A pair of `DefPathData` and an integer disambiguator. The integer is
141 /// normally `0`, but in the event that there are multiple defs with the
142 /// same `parent` and `data`, we use this field to disambiguate
143 /// between them. This introduces some artificial ordering dependency
144 /// but means that if you have, e.g., two impls for the same type in
145 /// the same module, they do get distinct `DefId`s.
146 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
147 pub struct DisambiguatedDefPathData {
148     pub data: DefPathData,
149     pub disambiguator: u32,
150 }
151
152 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
153 pub struct DefPath {
154     /// The path leading from the crate root to the item.
155     pub data: Vec<DisambiguatedDefPathData>,
156
157     /// The crate root this path is relative to.
158     pub krate: CrateNum,
159 }
160
161 impl DefPath {
162     pub fn is_local(&self) -> bool {
163         self.krate == LOCAL_CRATE
164     }
165
166     pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
167     where
168         FN: FnMut(DefIndex) -> DefKey,
169     {
170         let mut data = vec![];
171         let mut index = Some(start_index);
172         loop {
173             debug!("DefPath::make: krate={:?} index={:?}", krate, index);
174             let p = index.unwrap();
175             let key = get_key(p);
176             debug!("DefPath::make: key={:?}", key);
177             match key.disambiguated_data.data {
178                 DefPathData::CrateRoot => {
179                     assert!(key.parent.is_none());
180                     break;
181                 }
182                 _ => {
183                     data.push(key.disambiguated_data);
184                     index = key.parent;
185                 }
186             }
187         }
188         data.reverse();
189         DefPath { data, krate }
190     }
191
192     /// Returns a string representation of the `DefPath` without
193     /// the crate-prefix. This method is useful if you don't have
194     /// a `TyCtxt` available.
195     pub fn to_string_no_crate(&self) -> String {
196         let mut s = String::with_capacity(self.data.len() * 16);
197
198         for component in &self.data {
199             write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
200         }
201
202         s
203     }
204
205     /// Returns a filename-friendly string for the `DefPath`, with the
206     /// crate-prefix.
207     pub fn to_string_friendly<F>(&self, crate_imported_name: F) -> String
208     where
209         F: FnOnce(CrateNum) -> Symbol,
210     {
211         let crate_name_str = crate_imported_name(self.krate).as_str();
212         let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16);
213
214         write!(s, "::{}", crate_name_str).unwrap();
215
216         for component in &self.data {
217             if component.disambiguator == 0 {
218                 write!(s, "::{}", component.data.as_symbol()).unwrap();
219             } else {
220                 write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
221             }
222         }
223
224         s
225     }
226
227     /// Returns a filename-friendly string of the `DefPath`, without
228     /// the crate-prefix. This method is useful if you don't have
229     /// a `TyCtxt` available.
230     pub fn to_filename_friendly_no_crate(&self) -> String {
231         let mut s = String::with_capacity(self.data.len() * 16);
232
233         let mut opt_delimiter = None;
234         for component in &self.data {
235             s.extend(opt_delimiter);
236             opt_delimiter = Some('-');
237             if component.disambiguator == 0 {
238                 write!(s, "{}", component.data.as_symbol()).unwrap();
239             } else {
240                 write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
241             }
242         }
243         s
244     }
245 }
246
247 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
248 pub enum DefPathData {
249     // Root: these should only be used for the root nodes, because
250     // they are treated specially by the `def_path` function.
251     /// The crate root (marker).
252     CrateRoot,
253     // Catch-all for random `DefId` things like `DUMMY_NODE_ID`.
254     Misc,
255
256     // Different kinds of items and item-like things:
257     /// An impl.
258     Impl,
259     /// Something in the type namespace.
260     TypeNs(Symbol),
261     /// Something in the value namespace.
262     ValueNs(Symbol),
263     /// Something in the macro namespace.
264     MacroNs(Symbol),
265     /// Something in the lifetime namespace.
266     LifetimeNs(Symbol),
267     /// A closure expression.
268     ClosureExpr,
269
270     // Subportions of items:
271     /// Implicit constructor for a unit or tuple-like struct or enum variant.
272     Ctor,
273     /// A constant expression (see `{ast,hir}::AnonConst`).
274     AnonConst,
275     /// An `impl Trait` type node.
276     ImplTrait,
277 }
278
279 impl Definitions {
280     pub fn def_path_table(&self) -> &DefPathTable {
281         &self.table
282     }
283
284     /// Gets the number of definitions.
285     pub fn def_index_count(&self) -> usize {
286         self.table.index_to_key.len()
287     }
288
289     pub fn def_key(&self, id: LocalDefId) -> DefKey {
290         self.table.def_key(id.local_def_index)
291     }
292
293     #[inline(always)]
294     pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
295         self.table.def_path_hash(id.local_def_index)
296     }
297
298     /// Returns the path from the crate root to `index`. The root
299     /// nodes are not included in the path (i.e., this will be an
300     /// empty vector for the crate root). For an inlined item, this
301     /// will be the path of the item in the external crate (but the
302     /// path will begin with the path to the external crate).
303     pub fn def_path(&self, id: LocalDefId) -> DefPath {
304         DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
305             self.def_key(LocalDefId { local_def_index: index })
306         })
307     }
308
309     #[inline]
310     pub fn as_local_hir_id(&self, def_id: LocalDefId) -> hir::HirId {
311         self.local_def_id_to_hir_id(def_id)
312     }
313
314     #[inline]
315     pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
316         self.def_id_to_hir_id[id].unwrap()
317     }
318
319     #[inline]
320     pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option<hir::HirId> {
321         self.def_id_to_hir_id[id]
322     }
323
324     #[inline]
325     pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
326         self.hir_id_to_def_id.get(&hir_id).copied()
327     }
328
329     /// Adds a root definition (no parent) and a few other reserved definitions.
330     pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
331         let key = DefKey {
332             parent: None,
333             disambiguated_data: DisambiguatedDefPathData {
334                 data: DefPathData::CrateRoot,
335                 disambiguator: 0,
336             },
337         };
338
339         let parent_hash = DefKey::root_parent_stable_hash(crate_name, crate_disambiguator);
340         let def_path_hash = key.compute_stable_hash(parent_hash);
341
342         // Create the root definition.
343         let mut table = DefPathTable::default();
344         let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
345         assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
346
347         Definitions {
348             table,
349             def_id_to_hir_id: Default::default(),
350             hir_id_to_def_id: Default::default(),
351             expansions_that_defined: Default::default(),
352             parent_modules_of_macro_defs: Default::default(),
353         }
354     }
355
356     /// Retrieves the root definition.
357     pub fn get_root_def(&self) -> LocalDefId {
358         LocalDefId { local_def_index: CRATE_DEF_INDEX }
359     }
360
361     /// Adds a definition with a parent definition.
362     pub fn create_def(
363         &mut self,
364         parent: LocalDefId,
365         data: DefPathData,
366         expn_id: ExpnId,
367         mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
368     ) -> LocalDefId {
369         debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
370
371         // The root node must be created with `create_root_def()`.
372         assert!(data != DefPathData::CrateRoot);
373
374         let disambiguator = next_disambiguator(parent, data);
375         let key = DefKey {
376             parent: Some(parent.local_def_index),
377             disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
378         };
379
380         let parent_hash = self.table.def_path_hash(parent.local_def_index);
381         let def_path_hash = key.compute_stable_hash(parent_hash);
382
383         debug!("create_def: after disambiguation, key = {:?}", key);
384
385         // Create the definition.
386         let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
387
388         if expn_id != ExpnId::root() {
389             self.expansions_that_defined.insert(def_id, expn_id);
390         }
391
392         def_id
393     }
394
395     /// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
396     /// AST to HIR lowering.
397     pub fn init_def_id_to_hir_id_mapping(
398         &mut self,
399         mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
400     ) {
401         assert!(
402             self.def_id_to_hir_id.is_empty(),
403             "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
404         );
405
406         // Build the reverse mapping of `def_id_to_hir_id`.
407         self.hir_id_to_def_id = mapping
408             .iter_enumerated()
409             .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
410             .collect();
411
412         self.def_id_to_hir_id = mapping;
413     }
414
415     pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
416         self.expansions_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
417     }
418
419     pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
420         self.parent_modules_of_macro_defs[&expn_id]
421     }
422
423     pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
424         self.parent_modules_of_macro_defs.insert(expn_id, module);
425     }
426 }
427
428 impl DefPathData {
429     pub fn get_opt_name(&self) -> Option<Symbol> {
430         use self::DefPathData::*;
431         match *self {
432             TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
433
434             Impl | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => None,
435         }
436     }
437
438     pub fn as_symbol(&self) -> Symbol {
439         use self::DefPathData::*;
440         match *self {
441             TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => name,
442             // Note that this does not show up in user print-outs.
443             CrateRoot => sym::double_braced_crate,
444             Impl => sym::double_braced_impl,
445             Misc => sym::double_braced_misc,
446             ClosureExpr => sym::double_braced_closure,
447             Ctor => sym::double_braced_constructor,
448             AnonConst => sym::double_braced_constant,
449             ImplTrait => sym::double_braced_opaque,
450         }
451     }
452
453     pub fn to_string(&self) -> String {
454         self.as_symbol().to_string()
455     }
456 }