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 = {
51 let index = DefIndex::from(self.index_to_key.len());
52 debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
53 self.index_to_key.push(key);
54 index
55 };
56 self.def_path_hashes.push(local_hash);
57 debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
58
59 if let Some(existing) = self.def_path_hash_to_index.insert(&local_hash, &index) {
62 let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx));
63 let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx));
64
65 panic!(
74 "found DefPathHash collision between {def_path1:?} and {def_path2:?}. \
75 Compilation cannot continue."
76 );
77 }
78
79 index
80 }
81
82 #[inline(always)]
83 pub fn def_key(&self, index: DefIndex) -> DefKey {
84 self.index_to_key[index]
85 }
86
87 #[instrument(level = "trace", skip(self), ret)]
88 #[inline(always)]
89 pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
90 let hash = self.def_path_hashes[index];
91 DefPathHash::new(self.stable_crate_id, hash)
92 }
93
94 pub fn enumerated_keys_and_path_hashes(
95 &self,
96 ) -> impl Iterator<Item = (DefIndex, &DefKey, DefPathHash)> + ExactSizeIterator {
97 self.index_to_key
98 .iter_enumerated()
99 .map(move |(index, key)| (index, key, self.def_path_hash(index)))
100 }
101}
102
103#[derive(Debug)]
107pub struct Definitions {
108 table: DefPathTable,
109 next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>,
110}
111
112#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
116pub struct DefKey {
117 pub parent: Option<DefIndex>,
119
120 pub disambiguated_data: DisambiguatedDefPathData,
122}
123
124impl DefKey {
125 pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash {
126 let mut hasher = StableHasher::new();
127
128 parent.hash(&mut hasher);
129
130 let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
131
132 std::mem::discriminant(data).hash(&mut hasher);
133 if let Some(name) = data.get_opt_name() {
134 name.as_str().hash(&mut hasher);
137 }
138
139 disambiguator.hash(&mut hasher);
140
141 let local_hash = hasher.finish();
142
143 DefPathHash::new(parent.stable_crate_id(), local_hash)
148 }
149
150 #[inline]
151 pub fn get_opt_name(&self) -> Option<Symbol> {
152 self.disambiguated_data.data.get_opt_name()
153 }
154}
155
156#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
163pub struct DisambiguatedDefPathData {
164 pub data: DefPathData,
165 pub disambiguator: u32,
166}
167
168impl DisambiguatedDefPathData {
169 pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result {
170 match self.data.name() {
171 DefPathDataName::Named(name) => {
172 if verbose && self.disambiguator != 0 {
173 write!(writer, "{}#{}", name, self.disambiguator)
174 } else {
175 writer.write_str(name.as_str())
176 }
177 }
178 DefPathDataName::Anon { namespace } => {
179 write!(writer, "{{{}#{}}}", namespace, self.disambiguator)
180 }
181 }
182 }
183}
184
185impl fmt::Display for DisambiguatedDefPathData {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 self.fmt_maybe_verbose(f, true)
188 }
189}
190
191#[derive(Clone, Debug, Encodable, Decodable)]
192pub struct DefPath {
193 pub data: Vec<DisambiguatedDefPathData>,
195
196 pub krate: CrateNum,
198}
199
200impl DefPath {
201 pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
202 where
203 FN: FnMut(DefIndex) -> DefKey,
204 {
205 let mut data = vec![];
206 let mut index = Some(start_index);
207 loop {
208 debug!("DefPath::make: krate={:?} index={:?}", krate, index);
209 let p = index.unwrap();
210 let key = get_key(p);
211 debug!("DefPath::make: key={:?}", key);
212 match key.disambiguated_data.data {
213 DefPathData::CrateRoot => {
214 assert!(key.parent.is_none());
215 break;
216 }
217 _ => {
218 data.push(key.disambiguated_data);
219 index = key.parent;
220 }
221 }
222 }
223 data.reverse();
224 DefPath { data, krate }
225 }
226
227 pub fn to_string_no_crate_verbose(&self) -> String {
231 let mut s = String::with_capacity(self.data.len() * 16);
232
233 for component in &self.data {
234 write!(s, "::{component}").unwrap();
235 }
236
237 s
238 }
239
240 pub fn to_filename_friendly_no_crate(&self) -> String {
244 let mut s = String::with_capacity(self.data.len() * 16);
245
246 let mut opt_delimiter = None;
247 for component in &self.data {
248 s.extend(opt_delimiter);
249 opt_delimiter = Some('-');
250 write!(s, "{component}").unwrap();
251 }
252
253 s
254 }
255}
256
257#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
259pub enum DefPathData {
260 CrateRoot,
264
265 Impl,
268 ForeignMod,
270 Use,
272 GlobalAsm,
274 TypeNs(Option<Symbol>),
277 ValueNs(Symbol),
279 MacroNs(Symbol),
281 LifetimeNs(Symbol),
283 Closure,
285
286 Ctor,
289 AnonConst,
291 OpaqueTy,
294}
295
296impl Definitions {
297 pub fn def_path_table(&self) -> &DefPathTable {
298 &self.table
299 }
300
301 pub fn def_index_count(&self) -> usize {
303 self.table.index_to_key.len()
304 }
305
306 #[inline]
307 pub fn def_key(&self, id: LocalDefId) -> DefKey {
308 self.table.def_key(id.local_def_index)
309 }
310
311 #[inline(always)]
312 pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
313 self.table.def_path_hash(id.local_def_index)
314 }
315
316 pub fn def_path(&self, id: LocalDefId) -> DefPath {
322 DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
323 self.def_key(LocalDefId { local_def_index: index })
324 })
325 }
326
327 pub fn new(stable_crate_id: StableCrateId) -> Definitions {
329 let key = DefKey {
330 parent: None,
331 disambiguated_data: DisambiguatedDefPathData {
332 data: DefPathData::CrateRoot,
333 disambiguator: 0,
334 },
335 };
336
337 let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO);
338 let def_path_hash = key.compute_stable_hash(parent_hash);
339
340 let mut table = DefPathTable::new(stable_crate_id);
342 let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
343 assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
344
345 Definitions { table, next_disambiguator: Default::default() }
346 }
347
348 pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
350 debug!(
353 "create_def(parent={}, data={data:?})",
354 self.def_path(parent).to_string_no_crate_verbose(),
355 );
356
357 assert!(data != DefPathData::CrateRoot);
359
360 let disambiguator = {
362 let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
363 let disambiguator = *next_disamb;
364 *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
365 disambiguator
366 };
367 let key = DefKey {
368 parent: Some(parent.local_def_index),
369 disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
370 };
371
372 let parent_hash = self.table.def_path_hash(parent.local_def_index);
373 let def_path_hash = key.compute_stable_hash(parent_hash);
374
375 debug!("create_def: after disambiguation, key = {:?}", key);
376
377 LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) }
379 }
380
381 #[inline(always)]
382 pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
388 debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id);
389 self.table
390 .def_path_hash_to_index
391 .get(&hash.local_hash())
392 .map(|local_def_index| LocalDefId { local_def_index })
393 }
394
395 pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
396 &self.table.def_path_hash_to_index
397 }
398
399 pub fn num_definitions(&self) -> usize {
400 self.table.def_path_hashes.len()
401 }
402}
403
404#[derive(Copy, Clone, PartialEq, Debug)]
405pub enum DefPathDataName {
406 Named(Symbol),
407 Anon { namespace: Symbol },
408}
409
410impl DefPathData {
411 pub fn get_opt_name(&self) -> Option<Symbol> {
412 use self::DefPathData::*;
413 match *self {
414 TypeNs(name) => name,
415
416 ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
417
418 Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
419 | OpaqueTy => None,
420 }
421 }
422
423 pub fn name(&self) -> DefPathDataName {
424 use self::DefPathData::*;
425 match *self {
426 TypeNs(name) => {
427 if let Some(name) = name {
428 DefPathDataName::Named(name)
429 } else {
430 DefPathDataName::Anon { namespace: sym::synthetic }
431 }
432 }
433 ValueNs(name) | MacroNs(name) | LifetimeNs(name) => DefPathDataName::Named(name),
434 CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
436 Impl => DefPathDataName::Anon { namespace: kw::Impl },
437 ForeignMod => DefPathDataName::Anon { namespace: kw::Extern },
438 Use => DefPathDataName::Anon { namespace: kw::Use },
439 GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm },
440 Closure => DefPathDataName::Anon { namespace: sym::closure },
441 Ctor => DefPathDataName::Anon { namespace: sym::constructor },
442 AnonConst => DefPathDataName::Anon { namespace: sym::constant },
443 OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
444 }
445 }
446}
447
448impl fmt::Display for DefPathData {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 match self.name() {
451 DefPathDataName::Named(name) => f.write_str(name.as_str()),
452 DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"),
454 }
455 }
456}