1use std::fmt::{self, Write};
8use std::hash::Hash;
9
10use rustc_data_structures::stable_hasher::StableHasher;
11use rustc_data_structures::unord::UnordMap;
12use rustc_hashes::Hash64;
13use rustc_index::IndexVec;
14use rustc_macros::{Decodable, Encodable};
15use rustc_span::{Symbol, kw, sym};
16use tracing::{debug, instrument};
17
18pub use crate::def_id::DefPathHash;
19use crate::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId};
20use crate::def_path_hash_map::DefPathHashMap;
21
22#[derive(Debug)]
27pub struct DefPathTable {
28 stable_crate_id: StableCrateId,
29 index_to_key: IndexVec<DefIndex, DefKey>,
30 def_path_hashes: IndexVec<DefIndex, Hash64>,
32 def_path_hash_to_index: DefPathHashMap,
33}
34
35impl DefPathTable {
36 fn new(stable_crate_id: StableCrateId) -> DefPathTable {
37 DefPathTable {
38 stable_crate_id,
39 index_to_key: Default::default(),
40 def_path_hashes: Default::default(),
41 def_path_hash_to_index: Default::default(),
42 }
43 }
44
45 fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
46 debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id());
48 let local_hash = def_path_hash.local_hash();
49
50 let index = self.index_to_key.push(key);
51 debug!("DefPathTable::insert() - {key:?} <-> {index:?}");
52
53 self.def_path_hashes.push(local_hash);
54 debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
55
56 if let Some(existing) = self.def_path_hash_to_index.insert(&local_hash, &index) {
59 let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx));
60 let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx));
61
62 panic!(
71 "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \
72 Compilation cannot continue."
73 );
74 }
75
76 index
77 }
78
79 #[inline(always)]
80 pub fn def_key(&self, index: DefIndex) -> DefKey {
81 self.index_to_key[index]
82 }
83
84 #[instrument(level = "trace", skip(self), ret)]
85 #[inline(always)]
86 pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
87 let hash = self.def_path_hashes[index];
88 DefPathHash::new(self.stable_crate_id, hash)
89 }
90
91 pub fn enumerated_keys_and_path_hashes(
92 &self,
93 ) -> impl Iterator<Item = (DefIndex, &DefKey, DefPathHash)> + ExactSizeIterator {
94 self.index_to_key
95 .iter_enumerated()
96 .map(move |(index, key)| (index, key, self.def_path_hash(index)))
97 }
98}
99
100#[derive(Debug)]
101pub struct DisambiguatorState {
102 next: UnordMap<(LocalDefId, DefPathData), u32>,
103}
104
105impl DisambiguatorState {
106 pub fn new() -> Self {
107 Self { next: Default::default() }
108 }
109
110 pub fn with(def_id: LocalDefId, data: DefPathData, index: u32) -> Self {
113 let mut this = Self::new();
114 this.next.insert((def_id, data), index);
115 this
116 }
117}
118
119#[derive(Debug)]
123pub struct Definitions {
124 table: DefPathTable,
125}
126
127#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
131pub struct DefKey {
132 pub parent: Option<DefIndex>,
134
135 pub disambiguated_data: DisambiguatedDefPathData,
137}
138
139impl DefKey {
140 pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash {
141 let mut hasher = StableHasher::new();
142
143 parent.local_hash().hash(&mut hasher);
146
147 let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
148
149 std::mem::discriminant(data).hash(&mut hasher);
150 if let Some(name) = data.hashed_symbol() {
151 name.as_str().hash(&mut hasher);
154 }
155
156 disambiguator.hash(&mut hasher);
157
158 let local_hash = hasher.finish();
159
160 DefPathHash::new(parent.stable_crate_id(), local_hash)
165 }
166
167 #[inline]
168 pub fn get_opt_name(&self) -> Option<Symbol> {
169 self.disambiguated_data.data.get_opt_name()
170 }
171}
172
173#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
180pub struct DisambiguatedDefPathData {
181 pub data: DefPathData,
182 pub disambiguator: u32,
183}
184
185impl DisambiguatedDefPathData {
186 pub fn as_sym(&self, verbose: bool) -> Symbol {
187 match self.data.name() {
188 DefPathDataName::Named(name) => {
189 if verbose && self.disambiguator != 0 {
190 Symbol::intern(&format!("{}#{}", name, self.disambiguator))
191 } else {
192 name
193 }
194 }
195 DefPathDataName::Anon { namespace } => {
196 if let DefPathData::AnonAssocTy(method) = self.data {
197 Symbol::intern(&format!("{}::{{{}#{}}}", method, namespace, self.disambiguator))
198 } else {
199 Symbol::intern(&format!("{{{}#{}}}", namespace, self.disambiguator))
200 }
201 }
202 }
203 }
204}
205
206#[derive(Clone, Debug, Encodable, Decodable)]
207pub struct DefPath {
208 pub data: Vec<DisambiguatedDefPathData>,
210
211 pub krate: CrateNum,
213}
214
215impl DefPath {
216 pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
217 where
218 FN: FnMut(DefIndex) -> DefKey,
219 {
220 let mut data = vec![];
221 let mut index = Some(start_index);
222 loop {
223 debug!("DefPath::make: krate={:?} index={:?}", krate, index);
224 let p = index.unwrap();
225 let key = get_key(p);
226 debug!("DefPath::make: key={:?}", key);
227 match key.disambiguated_data.data {
228 DefPathData::CrateRoot => {
229 assert!(key.parent.is_none());
230 break;
231 }
232 _ => {
233 data.push(key.disambiguated_data);
234 index = key.parent;
235 }
236 }
237 }
238 data.reverse();
239 DefPath { data, krate }
240 }
241
242 pub fn to_string_no_crate_verbose(&self) -> String {
246 let mut s = String::with_capacity(self.data.len() * 16);
247
248 for component in &self.data {
249 write!(s, "::{}", component.as_sym(true)).unwrap();
250 }
251
252 s
253 }
254
255 pub fn to_filename_friendly_no_crate(&self) -> String {
259 let mut s = String::with_capacity(self.data.len() * 16);
260
261 let mut opt_delimiter = None;
262 for component in &self.data {
263 s.extend(opt_delimiter);
264 opt_delimiter = Some('-');
265 write!(s, "{}", component.as_sym(true)).unwrap();
266 }
267
268 s
269 }
270}
271
272#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
274pub enum DefPathData {
275 CrateRoot,
279
280 Impl,
283 ForeignMod,
285 Use,
287 GlobalAsm,
289 TypeNs(Symbol),
291 ValueNs(Symbol),
293 MacroNs(Symbol),
295 LifetimeNs(Symbol),
297 Closure,
299
300 Ctor,
303 AnonConst,
305 OpaqueTy,
308 OpaqueLifetime(Symbol),
310 AnonAssocTy(Symbol),
313 SyntheticCoroutineBody,
315 NestedStatic,
317}
318
319impl Definitions {
320 pub fn def_path_table(&self) -> &DefPathTable {
321 &self.table
322 }
323
324 pub fn def_index_count(&self) -> usize {
326 self.table.index_to_key.len()
327 }
328
329 #[inline]
330 pub fn def_key(&self, id: LocalDefId) -> DefKey {
331 self.table.def_key(id.local_def_index)
332 }
333
334 #[inline(always)]
335 pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
336 self.table.def_path_hash(id.local_def_index)
337 }
338
339 pub fn def_path(&self, id: LocalDefId) -> DefPath {
345 DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
346 self.def_key(LocalDefId { local_def_index: index })
347 })
348 }
349
350 pub fn new(stable_crate_id: StableCrateId) -> Definitions {
352 let key = DefKey {
353 parent: None,
354 disambiguated_data: DisambiguatedDefPathData {
355 data: DefPathData::CrateRoot,
356 disambiguator: 0,
357 },
358 };
359
360 let def_path_hash =
369 DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64()));
370
371 let mut table = DefPathTable::new(stable_crate_id);
373 let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
374 assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
375
376 Definitions { table }
377 }
378
379 pub fn create_def(
385 &mut self,
386 parent: LocalDefId,
387 data: DefPathData,
388 disambiguator: &mut DisambiguatorState,
389 ) -> LocalDefId {
390 debug!(
393 "create_def(parent={}, data={data:?})",
394 self.def_path(parent).to_string_no_crate_verbose(),
395 );
396
397 assert!(data != DefPathData::CrateRoot);
399
400 let disambiguator = {
402 let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0);
403 let disambiguator = *next_disamb;
404 *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
405 disambiguator
406 };
407 let key = DefKey {
408 parent: Some(parent.local_def_index),
409 disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
410 };
411
412 let parent_hash = self.table.def_path_hash(parent.local_def_index);
413 let def_path_hash = key.compute_stable_hash(parent_hash);
414
415 debug!("create_def: after disambiguation, key = {:?}", key);
416
417 LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) }
419 }
420
421 #[inline(always)]
422 pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
428 debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id);
429 self.table
430 .def_path_hash_to_index
431 .get(&hash.local_hash())
432 .map(|local_def_index| LocalDefId { local_def_index })
433 }
434
435 pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
436 &self.table.def_path_hash_to_index
437 }
438
439 pub fn num_definitions(&self) -> usize {
440 self.table.def_path_hashes.len()
441 }
442}
443
444#[derive(Copy, Clone, PartialEq, Debug)]
445pub enum DefPathDataName {
446 Named(Symbol),
447 Anon { namespace: Symbol },
448}
449
450impl DefPathData {
451 pub fn get_opt_name(&self) -> Option<Symbol> {
452 use self::DefPathData::*;
453 match *self {
454 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
455 | OpaqueLifetime(name) => Some(name),
456
457 Impl
458 | ForeignMod
459 | CrateRoot
460 | Use
461 | GlobalAsm
462 | Closure
463 | Ctor
464 | AnonConst
465 | OpaqueTy
466 | AnonAssocTy(..)
467 | SyntheticCoroutineBody
468 | NestedStatic => None,
469 }
470 }
471
472 fn hashed_symbol(&self) -> Option<Symbol> {
473 use self::DefPathData::*;
474 match *self {
475 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name)
476 | OpaqueLifetime(name) => Some(name),
477
478 Impl
479 | ForeignMod
480 | CrateRoot
481 | Use
482 | GlobalAsm
483 | Closure
484 | Ctor
485 | AnonConst
486 | OpaqueTy
487 | SyntheticCoroutineBody
488 | NestedStatic => None,
489 }
490 }
491
492 pub fn name(&self) -> DefPathDataName {
493 use self::DefPathData::*;
494 match *self {
495 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
496 | OpaqueLifetime(name) => DefPathDataName::Named(name),
497 CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
499 Impl => DefPathDataName::Anon { namespace: kw::Impl },
500 ForeignMod => DefPathDataName::Anon { namespace: kw::Extern },
501 Use => DefPathDataName::Anon { namespace: kw::Use },
502 GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm },
503 Closure => DefPathDataName::Anon { namespace: sym::closure },
504 Ctor => DefPathDataName::Anon { namespace: sym::constructor },
505 AnonConst => DefPathDataName::Anon { namespace: sym::constant },
506 OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
507 AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc },
508 SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
509 NestedStatic => DefPathDataName::Anon { namespace: sym::nested },
510 }
511 }
512}
513
514impl fmt::Display for DefPathData {
515 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 match self.name() {
517 DefPathDataName::Named(name) => f.write_str(name.as_str()),
518 DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"),
520 }
521 }
522}