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 LateAnonConst,
307 DesugaredAnonymousLifetime,
309 OpaqueTy,
312 OpaqueLifetime(Symbol),
314 AnonAssocTy(Symbol),
317 SyntheticCoroutineBody,
319 NestedStatic,
321}
322
323impl Definitions {
324 pub fn def_path_table(&self) -> &DefPathTable {
325 &self.table
326 }
327
328 pub fn def_index_count(&self) -> usize {
330 self.table.index_to_key.len()
331 }
332
333 #[inline]
334 pub fn def_key(&self, id: LocalDefId) -> DefKey {
335 self.table.def_key(id.local_def_index)
336 }
337
338 #[inline(always)]
339 pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
340 self.table.def_path_hash(id.local_def_index)
341 }
342
343 pub fn def_path(&self, id: LocalDefId) -> DefPath {
349 DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
350 self.def_key(LocalDefId { local_def_index: index })
351 })
352 }
353
354 pub fn new(stable_crate_id: StableCrateId) -> Definitions {
356 let key = DefKey {
357 parent: None,
358 disambiguated_data: DisambiguatedDefPathData {
359 data: DefPathData::CrateRoot,
360 disambiguator: 0,
361 },
362 };
363
364 let def_path_hash =
373 DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64()));
374
375 let mut table = DefPathTable::new(stable_crate_id);
377 let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
378 assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
379
380 Definitions { table }
381 }
382
383 pub fn create_def(
389 &mut self,
390 parent: LocalDefId,
391 data: DefPathData,
392 disambiguator: &mut DisambiguatorState,
393 ) -> LocalDefId {
394 debug!(
397 "create_def(parent={}, data={data:?})",
398 self.def_path(parent).to_string_no_crate_verbose(),
399 );
400
401 assert!(data != DefPathData::CrateRoot);
403
404 let disambiguator = {
406 let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0);
407 let disambiguator = *next_disamb;
408 *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
409 disambiguator
410 };
411 let key = DefKey {
412 parent: Some(parent.local_def_index),
413 disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
414 };
415
416 let parent_hash = self.table.def_path_hash(parent.local_def_index);
417 let def_path_hash = key.compute_stable_hash(parent_hash);
418
419 debug!("create_def: after disambiguation, key = {:?}", key);
420
421 LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) }
423 }
424
425 #[inline(always)]
426 pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
432 debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id);
433 self.table
434 .def_path_hash_to_index
435 .get(&hash.local_hash())
436 .map(|local_def_index| LocalDefId { local_def_index })
437 }
438
439 pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
440 &self.table.def_path_hash_to_index
441 }
442
443 pub fn num_definitions(&self) -> usize {
444 self.table.def_path_hashes.len()
445 }
446}
447
448#[derive(Copy, Clone, PartialEq, Debug)]
449pub enum DefPathDataName {
450 Named(Symbol),
451 Anon { namespace: Symbol },
452}
453
454impl DefPathData {
455 pub fn get_opt_name(&self) -> Option<Symbol> {
456 use self::DefPathData::*;
457 match *self {
458 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
459 | OpaqueLifetime(name) => Some(name),
460
461 DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime),
462
463 Impl
464 | ForeignMod
465 | CrateRoot
466 | Use
467 | GlobalAsm
468 | Closure
469 | Ctor
470 | AnonConst
471 | LateAnonConst
472 | OpaqueTy
473 | AnonAssocTy(..)
474 | SyntheticCoroutineBody
475 | NestedStatic => None,
476 }
477 }
478
479 fn hashed_symbol(&self) -> Option<Symbol> {
480 use self::DefPathData::*;
481 match *self {
482 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name)
483 | OpaqueLifetime(name) => Some(name),
484
485 DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime),
486
487 Impl
488 | ForeignMod
489 | CrateRoot
490 | Use
491 | GlobalAsm
492 | Closure
493 | Ctor
494 | AnonConst
495 | LateAnonConst
496 | OpaqueTy
497 | SyntheticCoroutineBody
498 | NestedStatic => None,
499 }
500 }
501
502 pub fn name(&self) -> DefPathDataName {
503 use self::DefPathData::*;
504 match *self {
505 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
506 | OpaqueLifetime(name) => DefPathDataName::Named(name),
507 CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
509 Impl => DefPathDataName::Anon { namespace: kw::Impl },
510 ForeignMod => DefPathDataName::Anon { namespace: kw::Extern },
511 Use => DefPathDataName::Anon { namespace: kw::Use },
512 GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm },
513 Closure => DefPathDataName::Anon { namespace: sym::closure },
514 Ctor => DefPathDataName::Anon { namespace: sym::constructor },
515 AnonConst | LateAnonConst => DefPathDataName::Anon { namespace: sym::constant },
516 DesugaredAnonymousLifetime => DefPathDataName::Named(kw::UnderscoreLifetime),
517 OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
518 AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc },
519 SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
520 NestedStatic => DefPathDataName::Anon { namespace: sym::nested },
521 }
522 }
523}
524
525impl fmt::Display for DefPathData {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 match self.name() {
528 DefPathDataName::Named(name) => f.write_str(name.as_str()),
529 DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"),
531 }
532 }
533}