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, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE}; 9 use crate::def_path_hash_map::DefPathHashMap; 10 11 use rustc_data_structures::fx::FxHashMap; 12 use rustc_data_structures::stable_hasher::{Hash64, StableHasher}; 13 use rustc_index::IndexVec; 14 use rustc_span::symbol::{kw, sym, Symbol}; 15 16 use std::fmt::{self, Write}; 17 use std::hash::Hash; 18 19 /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa. 20 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey` 21 /// stores the `DefIndex` of its parent. 22 /// There is one `DefPathTable` for each crate. 23 #[derive(Clone, Default, Debug)] 24 pub struct DefPathTable { 25 index_to_key: IndexVec<DefIndex, DefKey>, 26 def_path_hashes: IndexVec<DefIndex, DefPathHash>, 27 def_path_hash_to_index: DefPathHashMap, 28 } 29 30 impl DefPathTable { allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex31 fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex { 32 let index = { 33 let index = DefIndex::from(self.index_to_key.len()); 34 debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); 35 self.index_to_key.push(key); 36 index 37 }; 38 self.def_path_hashes.push(def_path_hash); 39 debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); 40 41 // Check for hash collisions of DefPathHashes. These should be 42 // exceedingly rare. 43 if let Some(existing) = self.def_path_hash_to_index.insert(&def_path_hash, &index) { 44 let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx)); 45 let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx)); 46 47 // Continuing with colliding DefPathHashes can lead to correctness 48 // issues. We must abort compilation. 49 // 50 // The likelihood of such a collision is very small, so actually 51 // running into one could be indicative of a poor hash function 52 // being used. 53 // 54 // See the documentation for DefPathHash for more information. 55 panic!( 56 "found DefPathHash collision between {def_path1:?} and {def_path2:?}. \ 57 Compilation cannot continue." 58 ); 59 } 60 61 // Assert that all DefPathHashes correctly contain the local crate's 62 // StableCrateId 63 #[cfg(debug_assertions)] 64 if let Some(root) = self.def_path_hashes.get(CRATE_DEF_INDEX) { 65 assert!(def_path_hash.stable_crate_id() == root.stable_crate_id()); 66 } 67 68 index 69 } 70 71 #[inline(always)] def_key(&self, index: DefIndex) -> DefKey72 pub fn def_key(&self, index: DefIndex) -> DefKey { 73 self.index_to_key[index] 74 } 75 76 #[inline(always)] def_path_hash(&self, index: DefIndex) -> DefPathHash77 pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { 78 let hash = self.def_path_hashes[index]; 79 debug!("def_path_hash({:?}) = {:?}", index, hash); 80 hash 81 } 82 enumerated_keys_and_path_hashes( &self, ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + ExactSizeIterator + '_83 pub fn enumerated_keys_and_path_hashes( 84 &self, 85 ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + ExactSizeIterator + '_ { 86 self.index_to_key 87 .iter_enumerated() 88 .map(move |(index, key)| (index, key, &self.def_path_hashes[index])) 89 } 90 } 91 92 /// The definition table containing node definitions. 93 /// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s. 94 /// It also stores mappings to convert `LocalDefId`s to/from `HirId`s. 95 #[derive(Debug)] 96 pub struct Definitions { 97 table: DefPathTable, 98 next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, 99 100 /// The [StableCrateId] of the local crate. 101 stable_crate_id: StableCrateId, 102 } 103 104 /// A unique identifier that we can use to lookup a definition 105 /// precisely. It combines the index of the definition's parent (if 106 /// any) with a `DisambiguatedDefPathData`. 107 #[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)] 108 pub struct DefKey { 109 /// The parent path. 110 pub parent: Option<DefIndex>, 111 112 /// The identifier of this node. 113 pub disambiguated_data: DisambiguatedDefPathData, 114 } 115 116 impl DefKey { compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash117 pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash { 118 let mut hasher = StableHasher::new(); 119 120 parent.hash(&mut hasher); 121 122 let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; 123 124 std::mem::discriminant(data).hash(&mut hasher); 125 if let Some(name) = data.get_opt_name() { 126 // Get a stable hash by considering the symbol chars rather than 127 // the symbol index. 128 name.as_str().hash(&mut hasher); 129 } 130 131 disambiguator.hash(&mut hasher); 132 133 let local_hash = hasher.finish(); 134 135 // Construct the new DefPathHash, making sure that the `crate_id` 136 // portion of the hash is properly copied from the parent. This way the 137 // `crate_id` part will be recursively propagated from the root to all 138 // DefPathHashes in this DefPathTable. 139 DefPathHash::new(parent.stable_crate_id(), local_hash) 140 } 141 142 #[inline] get_opt_name(&self) -> Option<Symbol>143 pub fn get_opt_name(&self) -> Option<Symbol> { 144 self.disambiguated_data.data.get_opt_name() 145 } 146 } 147 148 /// A pair of `DefPathData` and an integer disambiguator. The integer is 149 /// normally `0`, but in the event that there are multiple defs with the 150 /// same `parent` and `data`, we use this field to disambiguate 151 /// between them. This introduces some artificial ordering dependency 152 /// but means that if you have, e.g., two impls for the same type in 153 /// the same module, they do get distinct `DefId`s. 154 #[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)] 155 pub struct DisambiguatedDefPathData { 156 pub data: DefPathData, 157 pub disambiguator: u32, 158 } 159 160 impl DisambiguatedDefPathData { fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result161 pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { 162 match self.data.name() { 163 DefPathDataName::Named(name) => { 164 if verbose && self.disambiguator != 0 { 165 write!(writer, "{}#{}", name, self.disambiguator) 166 } else { 167 writer.write_str(name.as_str()) 168 } 169 } 170 DefPathDataName::Anon { namespace } => { 171 write!(writer, "{{{}#{}}}", namespace, self.disambiguator) 172 } 173 } 174 } 175 } 176 177 impl fmt::Display for DisambiguatedDefPathData { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 179 self.fmt_maybe_verbose(f, true) 180 } 181 } 182 183 #[derive(Clone, Debug, Encodable, Decodable)] 184 pub struct DefPath { 185 /// The path leading from the crate root to the item. 186 pub data: Vec<DisambiguatedDefPathData>, 187 188 /// The crate root this path is relative to. 189 pub krate: CrateNum, 190 } 191 192 impl DefPath { make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath where FN: FnMut(DefIndex) -> DefKey,193 pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath 194 where 195 FN: FnMut(DefIndex) -> DefKey, 196 { 197 let mut data = vec![]; 198 let mut index = Some(start_index); 199 loop { 200 debug!("DefPath::make: krate={:?} index={:?}", krate, index); 201 let p = index.unwrap(); 202 let key = get_key(p); 203 debug!("DefPath::make: key={:?}", key); 204 match key.disambiguated_data.data { 205 DefPathData::CrateRoot => { 206 assert!(key.parent.is_none()); 207 break; 208 } 209 _ => { 210 data.push(key.disambiguated_data); 211 index = key.parent; 212 } 213 } 214 } 215 data.reverse(); 216 DefPath { data, krate } 217 } 218 219 /// Returns a string representation of the `DefPath` without 220 /// the crate-prefix. This method is useful if you don't have 221 /// a `TyCtxt` available. to_string_no_crate_verbose(&self) -> String222 pub fn to_string_no_crate_verbose(&self) -> String { 223 let mut s = String::with_capacity(self.data.len() * 16); 224 225 for component in &self.data { 226 write!(s, "::{component}").unwrap(); 227 } 228 229 s 230 } 231 232 /// Returns a filename-friendly string of the `DefPath`, without 233 /// the crate-prefix. This method is useful if you don't have 234 /// a `TyCtxt` available. to_filename_friendly_no_crate(&self) -> String235 pub fn to_filename_friendly_no_crate(&self) -> String { 236 let mut s = String::with_capacity(self.data.len() * 16); 237 238 let mut opt_delimiter = None; 239 for component in &self.data { 240 s.extend(opt_delimiter); 241 opt_delimiter = Some('-'); 242 write!(s, "{component}").unwrap(); 243 } 244 245 s 246 } 247 } 248 249 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] 250 pub enum DefPathData { 251 // Root: these should only be used for the root nodes, because 252 // they are treated specially by the `def_path` function. 253 /// The crate root (marker). 254 CrateRoot, 255 256 // Different kinds of items and item-like things: 257 /// An impl. 258 Impl, 259 /// An `extern` block. 260 ForeignMod, 261 /// A `use` item. 262 Use, 263 /// A global asm item. 264 GlobalAsm, 265 /// Something in the type namespace. 266 TypeNs(Symbol), 267 /// Something in the value namespace. 268 ValueNs(Symbol), 269 /// Something in the macro namespace. 270 MacroNs(Symbol), 271 /// Something in the lifetime namespace. 272 LifetimeNs(Symbol), 273 /// A closure expression. 274 ClosureExpr, 275 276 // Subportions of items: 277 /// Implicit constructor for a unit or tuple-like struct or enum variant. 278 Ctor, 279 /// A constant expression (see `{ast,hir}::AnonConst`). 280 AnonConst, 281 /// An `impl Trait` type node. 282 ImplTrait, 283 /// `impl Trait` generated associated type node. 284 ImplTraitAssocTy, 285 } 286 287 impl Definitions { def_path_table(&self) -> &DefPathTable288 pub fn def_path_table(&self) -> &DefPathTable { 289 &self.table 290 } 291 292 /// Gets the number of definitions. def_index_count(&self) -> usize293 pub fn def_index_count(&self) -> usize { 294 self.table.index_to_key.len() 295 } 296 297 #[inline] def_key(&self, id: LocalDefId) -> DefKey298 pub fn def_key(&self, id: LocalDefId) -> DefKey { 299 self.table.def_key(id.local_def_index) 300 } 301 302 #[inline(always)] def_path_hash(&self, id: LocalDefId) -> DefPathHash303 pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash { 304 self.table.def_path_hash(id.local_def_index) 305 } 306 307 /// Returns the path from the crate root to `index`. The root 308 /// nodes are not included in the path (i.e., this will be an 309 /// empty vector for the crate root). For an inlined item, this 310 /// will be the path of the item in the external crate (but the 311 /// path will begin with the path to the external crate). def_path(&self, id: LocalDefId) -> DefPath312 pub fn def_path(&self, id: LocalDefId) -> DefPath { 313 DefPath::make(LOCAL_CRATE, id.local_def_index, |index| { 314 self.def_key(LocalDefId { local_def_index: index }) 315 }) 316 } 317 318 /// Adds a root definition (no parent) and a few other reserved definitions. new(stable_crate_id: StableCrateId) -> Definitions319 pub fn new(stable_crate_id: StableCrateId) -> Definitions { 320 let key = DefKey { 321 parent: None, 322 disambiguated_data: DisambiguatedDefPathData { 323 data: DefPathData::CrateRoot, 324 disambiguator: 0, 325 }, 326 }; 327 328 let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); 329 let def_path_hash = key.compute_stable_hash(parent_hash); 330 331 // Create the root definition. 332 let mut table = DefPathTable::default(); 333 let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) }; 334 assert_eq!(root.local_def_index, CRATE_DEF_INDEX); 335 336 Definitions { table, next_disambiguator: Default::default(), stable_crate_id } 337 } 338 339 /// Adds a definition with a parent definition. create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId340 pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId { 341 // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a 342 // reference to `Definitions` and we're already holding a mutable reference. 343 debug!( 344 "create_def(parent={}, data={data:?})", 345 self.def_path(parent).to_string_no_crate_verbose(), 346 ); 347 348 // The root node must be created with `create_root_def()`. 349 assert!(data != DefPathData::CrateRoot); 350 351 // Find the next free disambiguator for this key. 352 let disambiguator = { 353 let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0); 354 let disambiguator = *next_disamb; 355 *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); 356 disambiguator 357 }; 358 let key = DefKey { 359 parent: Some(parent.local_def_index), 360 disambiguated_data: DisambiguatedDefPathData { data, disambiguator }, 361 }; 362 363 let parent_hash = self.table.def_path_hash(parent.local_def_index); 364 let def_path_hash = key.compute_stable_hash(parent_hash); 365 366 debug!("create_def: after disambiguation, key = {:?}", key); 367 368 // Create the definition. 369 LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) } 370 } 371 372 #[inline(always)] local_def_path_hash_to_def_id( &self, hash: DefPathHash, err: &mut dyn FnMut() -> !, ) -> LocalDefId373 pub fn local_def_path_hash_to_def_id( 374 &self, 375 hash: DefPathHash, 376 err: &mut dyn FnMut() -> !, 377 ) -> LocalDefId { 378 debug_assert!(hash.stable_crate_id() == self.stable_crate_id); 379 self.table 380 .def_path_hash_to_index 381 .get(&hash) 382 .map(|local_def_index| LocalDefId { local_def_index }) 383 .unwrap_or_else(|| err()) 384 } 385 def_path_hash_to_def_index_map(&self) -> &DefPathHashMap386 pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap { 387 &self.table.def_path_hash_to_index 388 } 389 num_definitions(&self) -> usize390 pub fn num_definitions(&self) -> usize { 391 self.table.def_path_hashes.len() 392 } 393 } 394 395 #[derive(Copy, Clone, PartialEq, Debug)] 396 pub enum DefPathDataName { 397 Named(Symbol), 398 Anon { namespace: Symbol }, 399 } 400 401 impl DefPathData { get_opt_name(&self) -> Option<Symbol>402 pub fn get_opt_name(&self) -> Option<Symbol> { 403 use self::DefPathData::*; 404 match *self { 405 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), 406 407 Impl | ForeignMod | CrateRoot | Use | GlobalAsm | ClosureExpr | Ctor | AnonConst 408 | ImplTrait | ImplTraitAssocTy => None, 409 } 410 } 411 name(&self) -> DefPathDataName412 pub fn name(&self) -> DefPathDataName { 413 use self::DefPathData::*; 414 match *self { 415 TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { 416 DefPathDataName::Named(name) 417 } 418 // Note that this does not show up in user print-outs. 419 CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, 420 Impl => DefPathDataName::Anon { namespace: kw::Impl }, 421 ForeignMod => DefPathDataName::Anon { namespace: kw::Extern }, 422 Use => DefPathDataName::Anon { namespace: kw::Use }, 423 GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm }, 424 ClosureExpr => DefPathDataName::Anon { namespace: sym::closure }, 425 Ctor => DefPathDataName::Anon { namespace: sym::constructor }, 426 AnonConst => DefPathDataName::Anon { namespace: sym::constant }, 427 ImplTrait | ImplTraitAssocTy => DefPathDataName::Anon { namespace: sym::opaque }, 428 } 429 } 430 } 431 432 impl fmt::Display for DefPathData { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 434 match self.name() { 435 DefPathDataName::Named(name) => f.write_str(name.as_str()), 436 // FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc 437 DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"), 438 } 439 } 440 } 441