|  | //! For each definition, we track the following data. A definition | 
|  | //! here is defined somewhat circularly as "something with a `DefId`", | 
|  | //! but it generally corresponds to things like structs, enums, etc. | 
|  | //! There are also some rather random cases (like const initializer | 
|  | //! expressions) that are mostly just leftovers. | 
|  |  | 
|  | use std::fmt::{self, Write}; | 
|  | use std::hash::Hash; | 
|  |  | 
|  | use rustc_data_structures::stable_hasher::StableHasher; | 
|  | use rustc_data_structures::unord::UnordMap; | 
|  | use rustc_hashes::Hash64; | 
|  | use rustc_index::IndexVec; | 
|  | use rustc_macros::{Decodable, Encodable}; | 
|  | use rustc_span::{Symbol, kw, sym}; | 
|  | use tracing::{debug, instrument}; | 
|  |  | 
|  | pub use crate::def_id::DefPathHash; | 
|  | use crate::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId}; | 
|  | use crate::def_path_hash_map::DefPathHashMap; | 
|  |  | 
|  | /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa. | 
|  | /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey` | 
|  | /// stores the `DefIndex` of its parent. | 
|  | /// There is one `DefPathTable` for each crate. | 
|  | #[derive(Debug)] | 
|  | pub struct DefPathTable { | 
|  | stable_crate_id: StableCrateId, | 
|  | index_to_key: IndexVec<DefIndex, DefKey>, | 
|  | // We do only store the local hash, as all the definitions are from the current crate. | 
|  | def_path_hashes: IndexVec<DefIndex, Hash64>, | 
|  | def_path_hash_to_index: DefPathHashMap, | 
|  | } | 
|  |  | 
|  | impl DefPathTable { | 
|  | fn new(stable_crate_id: StableCrateId) -> DefPathTable { | 
|  | DefPathTable { | 
|  | stable_crate_id, | 
|  | index_to_key: Default::default(), | 
|  | def_path_hashes: Default::default(), | 
|  | def_path_hash_to_index: Default::default(), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex { | 
|  | // Assert that all DefPathHashes correctly contain the local crate's StableCrateId. | 
|  | debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id()); | 
|  | let local_hash = def_path_hash.local_hash(); | 
|  |  | 
|  | let index = self.index_to_key.push(key); | 
|  | debug!("DefPathTable::insert() - {key:?} <-> {index:?}"); | 
|  |  | 
|  | self.def_path_hashes.push(local_hash); | 
|  | debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); | 
|  |  | 
|  | // Check for hash collisions of DefPathHashes. These should be | 
|  | // exceedingly rare. | 
|  | if let Some(existing) = self.def_path_hash_to_index.insert(&local_hash, &index) { | 
|  | let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx)); | 
|  | let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx)); | 
|  |  | 
|  | // Continuing with colliding DefPathHashes can lead to correctness | 
|  | // issues. We must abort compilation. | 
|  | // | 
|  | // The likelihood of such a collision is very small, so actually | 
|  | // running into one could be indicative of a poor hash function | 
|  | // being used. | 
|  | // | 
|  | // See the documentation for DefPathHash for more information. | 
|  | panic!( | 
|  | "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \ | 
|  | Compilation cannot continue." | 
|  | ); | 
|  | } | 
|  |  | 
|  | index | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | pub fn def_key(&self, index: DefIndex) -> DefKey { | 
|  | self.index_to_key[index] | 
|  | } | 
|  |  | 
|  | #[instrument(level = "trace", skip(self), ret)] | 
|  | #[inline(always)] | 
|  | pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { | 
|  | let hash = self.def_path_hashes[index]; | 
|  | DefPathHash::new(self.stable_crate_id, hash) | 
|  | } | 
|  |  | 
|  | pub fn enumerated_keys_and_path_hashes( | 
|  | &self, | 
|  | ) -> impl Iterator<Item = (DefIndex, &DefKey, DefPathHash)> + ExactSizeIterator { | 
|  | self.index_to_key | 
|  | .iter_enumerated() | 
|  | .map(move |(index, key)| (index, key, self.def_path_hash(index))) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | pub struct DisambiguatorState { | 
|  | next: UnordMap<(LocalDefId, DefPathData), u32>, | 
|  | } | 
|  |  | 
|  | impl DisambiguatorState { | 
|  | pub fn new() -> Self { | 
|  | Self { next: Default::default() } | 
|  | } | 
|  |  | 
|  | /// Creates a `DisambiguatorState` where the next allocated `(LocalDefId, DefPathData)` pair | 
|  | /// will have `index` as the disambiguator. | 
|  | pub fn with(def_id: LocalDefId, data: DefPathData, index: u32) -> Self { | 
|  | let mut this = Self::new(); | 
|  | this.next.insert((def_id, data), index); | 
|  | this | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The definition table containing node definitions. | 
|  | /// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s. | 
|  | /// It also stores mappings to convert `LocalDefId`s to/from `HirId`s. | 
|  | #[derive(Debug)] | 
|  | pub struct Definitions { | 
|  | table: DefPathTable, | 
|  | } | 
|  |  | 
|  | /// A unique identifier that we can use to lookup a definition | 
|  | /// precisely. It combines the index of the definition's parent (if | 
|  | /// any) with a `DisambiguatedDefPathData`. | 
|  | #[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)] | 
|  | pub struct DefKey { | 
|  | /// The parent path. | 
|  | pub parent: Option<DefIndex>, | 
|  |  | 
|  | /// The identifier of this node. | 
|  | pub disambiguated_data: DisambiguatedDefPathData, | 
|  | } | 
|  |  | 
|  | impl DefKey { | 
|  | pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash { | 
|  | let mut hasher = StableHasher::new(); | 
|  |  | 
|  | // The new path is in the same crate as `parent`, and will contain the stable_crate_id. | 
|  | // Therefore, we only need to include information of the parent's local hash. | 
|  | parent.local_hash().hash(&mut hasher); | 
|  |  | 
|  | let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; | 
|  |  | 
|  | std::mem::discriminant(data).hash(&mut hasher); | 
|  | if let Some(name) = data.hashed_symbol() { | 
|  | // Get a stable hash by considering the symbol chars rather than | 
|  | // the symbol index. | 
|  | name.as_str().hash(&mut hasher); | 
|  | } | 
|  |  | 
|  | disambiguator.hash(&mut hasher); | 
|  |  | 
|  | let local_hash = hasher.finish(); | 
|  |  | 
|  | // Construct the new DefPathHash, making sure that the `crate_id` | 
|  | // portion of the hash is properly copied from the parent. This way the | 
|  | // `crate_id` part will be recursively propagated from the root to all | 
|  | // DefPathHashes in this DefPathTable. | 
|  | DefPathHash::new(parent.stable_crate_id(), local_hash) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn get_opt_name(&self) -> Option<Symbol> { | 
|  | self.disambiguated_data.data.get_opt_name() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A pair of `DefPathData` and an integer disambiguator. The integer is | 
|  | /// normally `0`, but in the event that there are multiple defs with the | 
|  | /// same `parent` and `data`, we use this field to disambiguate | 
|  | /// between them. This introduces some artificial ordering dependency | 
|  | /// but means that if you have, e.g., two impls for the same type in | 
|  | /// the same module, they do get distinct `DefId`s. | 
|  | #[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)] | 
|  | pub struct DisambiguatedDefPathData { | 
|  | pub data: DefPathData, | 
|  | pub disambiguator: u32, | 
|  | } | 
|  |  | 
|  | impl DisambiguatedDefPathData { | 
|  | pub fn as_sym(&self, verbose: bool) -> Symbol { | 
|  | match self.data.name() { | 
|  | DefPathDataName::Named(name) => { | 
|  | if verbose && self.disambiguator != 0 { | 
|  | Symbol::intern(&format!("{}#{}", name, self.disambiguator)) | 
|  | } else { | 
|  | name | 
|  | } | 
|  | } | 
|  | DefPathDataName::Anon { namespace } => { | 
|  | if let DefPathData::AnonAssocTy(method) = self.data { | 
|  | Symbol::intern(&format!("{}::{{{}#{}}}", method, namespace, self.disambiguator)) | 
|  | } else { | 
|  | Symbol::intern(&format!("{{{}#{}}}", namespace, self.disambiguator)) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Clone, Debug, Encodable, Decodable)] | 
|  | pub struct DefPath { | 
|  | /// The path leading from the crate root to the item. | 
|  | pub data: Vec<DisambiguatedDefPathData>, | 
|  |  | 
|  | /// The crate root this path is relative to. | 
|  | pub krate: CrateNum, | 
|  | } | 
|  |  | 
|  | impl DefPath { | 
|  | pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath | 
|  | where | 
|  | FN: FnMut(DefIndex) -> DefKey, | 
|  | { | 
|  | let mut data = vec![]; | 
|  | let mut index = Some(start_index); | 
|  | loop { | 
|  | debug!("DefPath::make: krate={:?} index={:?}", krate, index); | 
|  | let p = index.unwrap(); | 
|  | let key = get_key(p); | 
|  | debug!("DefPath::make: key={:?}", key); | 
|  | match key.disambiguated_data.data { | 
|  | DefPathData::CrateRoot => { | 
|  | assert!(key.parent.is_none()); | 
|  | break; | 
|  | } | 
|  | _ => { | 
|  | data.push(key.disambiguated_data); | 
|  | index = key.parent; | 
|  | } | 
|  | } | 
|  | } | 
|  | data.reverse(); | 
|  | DefPath { data, krate } | 
|  | } | 
|  |  | 
|  | /// Returns a string representation of the `DefPath` without | 
|  | /// the crate-prefix. This method is useful if you don't have | 
|  | /// a `TyCtxt` available. | 
|  | pub fn to_string_no_crate_verbose(&self) -> String { | 
|  | let mut s = String::with_capacity(self.data.len() * 16); | 
|  |  | 
|  | for component in &self.data { | 
|  | write!(s, "::{}", component.as_sym(true)).unwrap(); | 
|  | } | 
|  |  | 
|  | s | 
|  | } | 
|  |  | 
|  | /// Returns a filename-friendly string of the `DefPath`, without | 
|  | /// the crate-prefix. This method is useful if you don't have | 
|  | /// a `TyCtxt` available. | 
|  | pub fn to_filename_friendly_no_crate(&self) -> String { | 
|  | let mut s = String::with_capacity(self.data.len() * 16); | 
|  |  | 
|  | let mut opt_delimiter = None; | 
|  | for component in &self.data { | 
|  | s.extend(opt_delimiter); | 
|  | opt_delimiter = Some('-'); | 
|  | write!(s, "{}", component.as_sym(true)).unwrap(); | 
|  | } | 
|  |  | 
|  | s | 
|  | } | 
|  | } | 
|  |  | 
|  | /// New variants should only be added in synchronization with `enum DefKind`. | 
|  | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] | 
|  | pub enum DefPathData { | 
|  | // Root: these should only be used for the root nodes, because | 
|  | // they are treated specially by the `def_path` function. | 
|  | /// The crate root (marker). | 
|  | CrateRoot, | 
|  |  | 
|  | // Different kinds of items and item-like things: | 
|  | /// An impl. | 
|  | Impl, | 
|  | /// An `extern` block. | 
|  | ForeignMod, | 
|  | /// A `use` item. | 
|  | Use, | 
|  | /// A global asm item. | 
|  | GlobalAsm, | 
|  | /// Something in the type namespace. | 
|  | TypeNs(Symbol), | 
|  | /// Something in the value namespace. | 
|  | ValueNs(Symbol), | 
|  | /// Something in the macro namespace. | 
|  | MacroNs(Symbol), | 
|  | /// Something in the lifetime namespace. | 
|  | LifetimeNs(Symbol), | 
|  | /// A closure expression. | 
|  | Closure, | 
|  |  | 
|  | // Subportions of items: | 
|  | /// Implicit constructor for a unit or tuple-like struct or enum variant. | 
|  | Ctor, | 
|  | /// A constant expression (see `{ast,hir}::AnonConst`). | 
|  | AnonConst, | 
|  | /// A constant expression created during AST->HIR lowering.. | 
|  | LateAnonConst, | 
|  | /// A fresh anonymous lifetime created by desugaring elided lifetimes. | 
|  | DesugaredAnonymousLifetime, | 
|  | /// An existential `impl Trait` type node. | 
|  | /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. | 
|  | OpaqueTy, | 
|  | /// Used for remapped captured lifetimes in an existential `impl Trait` type node. | 
|  | OpaqueLifetime(Symbol), | 
|  | /// An anonymous associated type from an RPITIT. The symbol refers to the name of the method | 
|  | /// that defined the type. | 
|  | AnonAssocTy(Symbol), | 
|  | /// A synthetic body for a coroutine's by-move body. | 
|  | SyntheticCoroutineBody, | 
|  | /// Additional static data referred to by a static. | 
|  | NestedStatic, | 
|  | } | 
|  |  | 
|  | impl Definitions { | 
|  | pub fn def_path_table(&self) -> &DefPathTable { | 
|  | &self.table | 
|  | } | 
|  |  | 
|  | /// Gets the number of definitions. | 
|  | pub fn def_index_count(&self) -> usize { | 
|  | self.table.index_to_key.len() | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn def_key(&self, id: LocalDefId) -> DefKey { | 
|  | self.table.def_key(id.local_def_index) | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash { | 
|  | self.table.def_path_hash(id.local_def_index) | 
|  | } | 
|  |  | 
|  | /// Returns the path from the crate root to `index`. The root | 
|  | /// nodes are not included in the path (i.e., this will be an | 
|  | /// empty vector for the crate root). For an inlined item, this | 
|  | /// will be the path of the item in the external crate (but the | 
|  | /// path will begin with the path to the external crate). | 
|  | pub fn def_path(&self, id: LocalDefId) -> DefPath { | 
|  | DefPath::make(LOCAL_CRATE, id.local_def_index, |index| { | 
|  | self.def_key(LocalDefId { local_def_index: index }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | /// Adds a root definition (no parent) and a few other reserved definitions. | 
|  | pub fn new(stable_crate_id: StableCrateId) -> Definitions { | 
|  | let key = DefKey { | 
|  | parent: None, | 
|  | disambiguated_data: DisambiguatedDefPathData { | 
|  | data: DefPathData::CrateRoot, | 
|  | disambiguator: 0, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | // We want *both* halves of a DefPathHash to depend on the crate-id of the defining crate. | 
|  | // The crate-id can be more easily changed than the DefPath of an item, so, in the case of | 
|  | // a crate-local DefPathHash collision, the user can simply "roll the dice again" for all | 
|  | // DefPathHashes in the crate by changing the crate disambiguator (e.g. via bumping the | 
|  | // crate's version number). | 
|  | // | 
|  | // Children paths will only hash the local portion, and still inherit the change to the | 
|  | // root hash. | 
|  | let def_path_hash = | 
|  | DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64())); | 
|  |  | 
|  | // Create the root definition. | 
|  | let mut table = DefPathTable::new(stable_crate_id); | 
|  | let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) }; | 
|  | assert_eq!(root.local_def_index, CRATE_DEF_INDEX); | 
|  |  | 
|  | Definitions { table } | 
|  | } | 
|  |  | 
|  | /// Creates a definition with a parent definition. | 
|  | /// If there are multiple definitions with the same DefPathData and the same parent, use | 
|  | /// `disambiguator` to differentiate them. Distinct `DisambiguatorState` instances are not | 
|  | /// guaranteed to generate unique disambiguators and should instead ensure that the `parent` | 
|  | /// and `data` pair is distinct from other instances. | 
|  | pub fn create_def( | 
|  | &mut self, | 
|  | parent: LocalDefId, | 
|  | data: DefPathData, | 
|  | disambiguator: &mut DisambiguatorState, | 
|  | ) -> LocalDefId { | 
|  | // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a | 
|  | // reference to `Definitions` and we're already holding a mutable reference. | 
|  | debug!( | 
|  | "create_def(parent={}, data={data:?})", | 
|  | self.def_path(parent).to_string_no_crate_verbose(), | 
|  | ); | 
|  |  | 
|  | // The root node must be created in `new()`. | 
|  | assert!(data != DefPathData::CrateRoot); | 
|  |  | 
|  | // Find the next free disambiguator for this key. | 
|  | let disambiguator = { | 
|  | let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0); | 
|  | let disambiguator = *next_disamb; | 
|  | *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); | 
|  | disambiguator | 
|  | }; | 
|  | let key = DefKey { | 
|  | parent: Some(parent.local_def_index), | 
|  | disambiguated_data: DisambiguatedDefPathData { data, disambiguator }, | 
|  | }; | 
|  |  | 
|  | let parent_hash = self.table.def_path_hash(parent.local_def_index); | 
|  | let def_path_hash = key.compute_stable_hash(parent_hash); | 
|  |  | 
|  | debug!("create_def: after disambiguation, key = {:?}", key); | 
|  |  | 
|  | // Create the definition. | 
|  | LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) } | 
|  | } | 
|  |  | 
|  | #[inline(always)] | 
|  | /// Returns `None` if the `DefPathHash` does not correspond to a `LocalDefId` | 
|  | /// in the current compilation session. This can legitimately happen if the | 
|  | /// `DefPathHash` is from a `DefId` in an upstream crate or, during incr. comp., | 
|  | /// if the `DefPathHash` is from a previous compilation session and | 
|  | /// the def-path does not exist anymore. | 
|  | pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> { | 
|  | debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id); | 
|  | self.table | 
|  | .def_path_hash_to_index | 
|  | .get(&hash.local_hash()) | 
|  | .map(|local_def_index| LocalDefId { local_def_index }) | 
|  | } | 
|  |  | 
|  | pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap { | 
|  | &self.table.def_path_hash_to_index | 
|  | } | 
|  |  | 
|  | pub fn num_definitions(&self) -> usize { | 
|  | self.table.def_path_hashes.len() | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Copy, Clone, PartialEq, Debug)] | 
|  | pub enum DefPathDataName { | 
|  | Named(Symbol), | 
|  | Anon { namespace: Symbol }, | 
|  | } | 
|  |  | 
|  | impl DefPathData { | 
|  | pub fn get_opt_name(&self) -> Option<Symbol> { | 
|  | use self::DefPathData::*; | 
|  | match *self { | 
|  | TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | 
|  | | OpaqueLifetime(name) => Some(name), | 
|  |  | 
|  | DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime), | 
|  |  | 
|  | Impl | 
|  | | ForeignMod | 
|  | | CrateRoot | 
|  | | Use | 
|  | | GlobalAsm | 
|  | | Closure | 
|  | | Ctor | 
|  | | AnonConst | 
|  | | LateAnonConst | 
|  | | OpaqueTy | 
|  | | AnonAssocTy(..) | 
|  | | SyntheticCoroutineBody | 
|  | | NestedStatic => None, | 
|  | } | 
|  | } | 
|  |  | 
|  | fn hashed_symbol(&self) -> Option<Symbol> { | 
|  | use self::DefPathData::*; | 
|  | match *self { | 
|  | TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name) | 
|  | | OpaqueLifetime(name) => Some(name), | 
|  |  | 
|  | DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime), | 
|  |  | 
|  | Impl | 
|  | | ForeignMod | 
|  | | CrateRoot | 
|  | | Use | 
|  | | GlobalAsm | 
|  | | Closure | 
|  | | Ctor | 
|  | | AnonConst | 
|  | | LateAnonConst | 
|  | | OpaqueTy | 
|  | | SyntheticCoroutineBody | 
|  | | NestedStatic => None, | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn name(&self) -> DefPathDataName { | 
|  | use self::DefPathData::*; | 
|  | match *self { | 
|  | TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | 
|  | | OpaqueLifetime(name) => DefPathDataName::Named(name), | 
|  | // Note that this does not show up in user print-outs. | 
|  | CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, | 
|  | Impl => DefPathDataName::Anon { namespace: kw::Impl }, | 
|  | ForeignMod => DefPathDataName::Anon { namespace: kw::Extern }, | 
|  | Use => DefPathDataName::Anon { namespace: kw::Use }, | 
|  | GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm }, | 
|  | Closure => DefPathDataName::Anon { namespace: sym::closure }, | 
|  | Ctor => DefPathDataName::Anon { namespace: sym::constructor }, | 
|  | AnonConst | LateAnonConst => DefPathDataName::Anon { namespace: sym::constant }, | 
|  | DesugaredAnonymousLifetime => DefPathDataName::Named(kw::UnderscoreLifetime), | 
|  | OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, | 
|  | AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc }, | 
|  | SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, | 
|  | NestedStatic => DefPathDataName::Anon { namespace: sym::nested }, | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl fmt::Display for DefPathData { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | match self.name() { | 
|  | DefPathDataName::Named(name) => f.write_str(name.as_str()), | 
|  | // FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc | 
|  | DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"), | 
|  | } | 
|  | } | 
|  | } |