Skip to main content

charon_driver/hax/types/
def_id.rs

1//! This module contains the type definition for `DefId` and the types
2//! `DefId` depends on.
3//!
4//! This is purposely a very small isolated module:
5//! `hax-engine-names-extract` uses those types, but we don't want
6//! `hax-engine-names-extract` to have a build dependency on the whole
7//! frontend, that double the build times for the Rust part of hax.
8
9use crate::hax::AdtInto;
10use crate::hax::prelude::*;
11use charon_lib::ast::HashConsed;
12
13use itertools::Itertools;
14pub use rustc_middle::mir::Promoted as PromotedId;
15use rustc_span::DUMMY_SP;
16use {rustc_hir as hir, rustc_hir::def_id::DefId as RDefId, rustc_middle::ty};
17
18sinto_reexport!(hir::Safety);
19sinto_reexport!(hir::Mutability);
20sinto_reexport!(hir::def::CtorKind);
21sinto_reexport!(hir::def::MacroKinds);
22sinto_reexport!(hir::def::CtorOf);
23sinto_reexport!(rustc_span::symbol::Symbol);
24sinto_reexport!(rustc_span::symbol::ByteSymbol);
25
26/// Reflects [`rustc_hir::def::DefKind`]
27#[derive(AdtInto)]
28#[args(<S>, from: rustc_hir::def::DefKind, state: S as tcx)]
29#[derive(Debug, Clone, PartialEq, Hash, Eq)]
30pub enum DefKind {
31    Mod,
32    Struct,
33    Union,
34    Enum,
35    Variant,
36    Trait,
37    TyAlias,
38    ForeignTy,
39    TraitAlias,
40    AssocTy,
41    TyParam,
42    Fn,
43    Const {
44        is_type_const: bool,
45    },
46    ConstParam,
47    Static {
48        safety: Safety,
49        mutability: Mutability,
50        nested: bool,
51    },
52    Ctor(CtorOf, CtorKind),
53    AssocFn,
54    AssocConst {
55        is_type_const: bool,
56    },
57    Macro(MacroKinds),
58    ExternCrate,
59    Use,
60    ForeignMod,
61    AnonConst,
62    #[disable_mapping]
63    /// Added by hax: promoted constants don't have def_ids in rustc but they do in hax.
64    PromotedConst,
65    OpaqueTy,
66    Field,
67    LifetimeParam,
68    GlobalAsm,
69    Impl {
70        of_trait: bool,
71    },
72    Closure,
73    SyntheticCoroutineBody,
74}
75
76/// The crate name under which synthetic items are exported under.
77const SYNTHETIC_CRATE_NAME: &str = "<synthetic>";
78
79/// Reflects [`rustc_hir::def_id::DefId`], augmented to also give ids to promoted constants (which
80/// have their own ad-hoc numbering scheme in rustc for now).
81#[derive(Clone, PartialEq, Eq)]
82pub struct DefId {
83    pub(crate) contents: HashConsed<DefIdContents>,
84}
85
86#[derive(Debug, Hash, Clone, PartialEq, Eq)]
87pub struct DefIdContents {
88    pub base: DefIdBase,
89    /// The kind of definition this `DefId` points to.
90    pub kind: crate::hax::DefKind,
91}
92
93#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
94pub enum DefIdBase {
95    Real(RDefId),
96    Promoted(RDefId, PromotedId),
97    /// This represents the context made of the trait impl generics plus the associated item
98    /// generics declared in the trait. We use that context to trait solve the mapping from
99    /// declared method generics to implemented method generics.
100    ImplAssocItem(VirtualImplAssocItem),
101    /// A completely fictitious item, we use this for arrays, slices and tuples to make
102    /// monomorphization and other shenanigans easier.
103    Synthetic(SyntheticItem),
104}
105
106#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
107pub struct VirtualImplAssocItem {
108    /// The trait impl.
109    pub trait_impl_id: RDefId,
110    /// The item declaration.
111    pub item_decl_id: RDefId,
112    /// The item implementation.
113    pub item_impl_id: RDefId,
114}
115
116impl VirtualImplAssocItem {
117    pub fn new(trait_impl_id: RDefId, item_decl_id: RDefId, item_impl_id: RDefId) -> Self {
118        Self {
119            trait_impl_id,
120            item_decl_id,
121            item_impl_id,
122        }
123    }
124
125    /// Arguments just for the item itself (works for both decl and impl), valid in the virtual
126    /// item context.
127    fn own_args<'tcx>(&self, s: &impl BaseState<'tcx>) -> Vec<ty::GenericArg<'tcx>> {
128        let tcx = s.base().tcx;
129        DefId::make_assoc_item_impl(s, *self)
130            .generics_of(s)
131            .own_params
132            .iter()
133            .map(|param| tcx.mk_param_from_def(param))
134            .collect()
135    }
136
137    /// Construct generic args for the item declaration, valid in the virtual item context.
138    pub fn args_for_item_decl<'tcx>(
139        &self,
140        s: &impl BaseState<'tcx>,
141        trait_args: ty::GenericArgsRef<'tcx>,
142    ) -> ty::GenericArgsRef<'tcx> {
143        let tcx = s.base().tcx;
144        tcx.mk_args_from_iter(trait_args.iter().chain(self.own_args(s)))
145    }
146
147    /// Construct generic args for the item implementation, valid in the virtual item context.
148    pub fn args_for_item_impl<'tcx>(
149        &self,
150        s: &impl BaseState<'tcx>,
151        impl_args: ty::GenericArgsRef<'tcx>,
152    ) -> ty::GenericArgsRef<'tcx> {
153        let tcx = s.base().tcx;
154        tcx.mk_args_from_iter(impl_args.iter().chain(self.own_args(s)))
155    }
156
157    /// Construct generic args for the item declaration, valid in the virtual item context.
158    pub fn identity_args_for_item_decl<'tcx>(
159        &self,
160        s: &impl BaseState<'tcx>,
161    ) -> ty::GenericArgsRef<'tcx> {
162        let tcx = s.base().tcx;
163        let impl_trait_ref = tcx
164            .impl_trait_ref(self.trait_impl_id)
165            .instantiate_identity()
166            .skip_normalization();
167        self.args_for_item_decl(s, impl_trait_ref.args)
168    }
169}
170
171impl DefIdContents {
172    pub fn make_def_id<'tcx, S: BaseState<'tcx>>(self, _s: &S) -> DefId {
173        let contents = HashConsed::new(self);
174        DefId { contents }
175    }
176}
177
178impl rustc_trait_elaboration::ItemId for DefId {
179    type State<'tcx> = StateWithBase<'tcx>;
180
181    fn from_rust_def_id<'tcx>(s: &Self::State<'tcx>, def_id: RDefId) -> Self {
182        def_id.sinto(s)
183    }
184
185    fn generics_of<'tcx>(&self, s: &Self::State<'tcx>) -> &'tcx ty::Generics {
186        DefId::generics_of(self, s)
187    }
188
189    fn param_env<'tcx>(&self, s: &Self::State<'tcx>) -> ty::ParamEnv<'tcx> {
190        DefId::param_env(self, s)
191    }
192
193    fn predicates_defined_on<'tcx>(
194        &self,
195        s: &Self::State<'tcx>,
196        direction: PredicateDirection,
197    ) -> ItemPredicates<'tcx, Self> {
198        let tcx = s.base().tcx;
199        match self.base {
200            DefIdBase::Real(def_id) => ItemPredicates::defined_on(tcx, s, def_id, direction),
201            DefIdBase::ImplAssocItem(id) => {
202                let item_args = id.identity_args_for_item_decl(s);
203                ItemPredicates::defined_on(tcx, s, id.item_decl_id, direction)
204                    .instantiate(tcx, item_args)
205            }
206            DefIdBase::Synthetic(synthetic) => {
207                synthetic.predicates_defined_on(s, self.clone(), direction)
208            }
209            DefIdBase::Promoted(..) => ItemPredicates::new_unmapped(DUMMY_SP, []),
210        }
211    }
212
213    fn self_pred<'tcx>(&self, s: &Self::State<'tcx>) -> Option<ty::PolyTraitRef<'tcx>> {
214        let tcx = s.base().tcx;
215        match self.base {
216            DefIdBase::Real(def_id) => def_id.self_pred(&tcx),
217            _ => None,
218        }
219    }
220
221    fn as_identity_assoc_ty<'tcx>(&self, s: &Self::State<'tcx>) -> Option<ty::Ty<'tcx>> {
222        let tcx = s.base().tcx;
223        match self.base {
224            DefIdBase::Real(def_id) => def_id.as_identity_assoc_ty(&tcx),
225            _ => None,
226        }
227    }
228
229    fn typeck_parent<'tcx>(&self, s: &Self::State<'tcx>) -> Option<Self> {
230        let tcx = s.base().tcx;
231        match self.base {
232            DefIdBase::Real(def_id) => def_id.typeck_parent(&tcx).map(|def_id| def_id.sinto(s)),
233            DefIdBase::Promoted(def_id, ..) => Some(tcx.typeck_root_def_id(def_id).sinto(s)),
234            DefIdBase::ImplAssocItem(..) | DefIdBase::Synthetic(..) => None,
235        }
236    }
237
238    fn parent_of_assoc<'tcx>(&self, s: &Self::State<'tcx>) -> Option<Self> {
239        let tcx = s.base().tcx;
240        match self.base {
241            DefIdBase::Real(def_id) => def_id.parent_of_assoc(&tcx).map(|def_id| def_id.sinto(s)),
242            DefIdBase::ImplAssocItem(id) => Some(id.trait_impl_id.sinto(s)),
243            _ => None,
244        }
245    }
246
247    fn parent_for_clauses<'tcx>(&self, s: &Self::State<'tcx>) -> Option<Self> {
248        let tcx = s.base().tcx;
249        match self.base {
250            DefIdBase::Real(def_id) => def_id
251                .parent_for_clauses(&tcx)
252                .map(|def_id| def_id.sinto(s)),
253            DefIdBase::ImplAssocItem(id) => Some(id.trait_impl_id.sinto(s)),
254            DefIdBase::Promoted(def_id, _) => Some(def_id.sinto(s)),
255            DefIdBase::Synthetic(..) => None,
256        }
257    }
258
259    fn takes_explicit_self_clause<'tcx>(&self, s: &Self::State<'tcx>) -> bool {
260        let tcx = s.base().tcx;
261        match self.base {
262            DefIdBase::Real(def_id) | DefIdBase::Promoted(def_id, ..) => {
263                def_id.takes_explicit_self_clause(&tcx)
264            }
265            DefIdBase::ImplAssocItem(id) => id.item_decl_id.takes_explicit_self_clause(&tcx),
266            DefIdBase::Synthetic(..) => false,
267        }
268    }
269
270    fn find_in_impl<'tcx>(&self, s: &Self::State<'tcx>, trait_impl: &Self) -> Option<Self> {
271        let tcx = s.base().tcx;
272        let trait_impl = trait_impl.as_real_def_id()?;
273        match self.base {
274            DefIdBase::Real(def_id) => def_id
275                .find_in_impl(&tcx, &trait_impl)
276                .map(|def_id| def_id.sinto(s)),
277            _ => None,
278        }
279    }
280}
281
282impl DefId {
283    /// The rustc def_id corresponding to this item, if there is one. Promoted constants don't have
284    /// a rustc def_id.
285    pub fn as_real_def_id(&self) -> Option<RDefId> {
286        match self.base {
287            DefIdBase::Real(did) => Some(did),
288            _ => None,
289        }
290    }
291    /// The rustc def_id of this item. Panics if this is not a real rustc item.
292    pub fn real_rust_def_id(&self) -> RDefId {
293        self.as_real_def_id().unwrap()
294    }
295    /// The def_id of this item or its parent if this is a promoted constant.
296    pub fn as_real_or_promoted(&self) -> Option<RDefId> {
297        match self.base {
298            DefIdBase::Real(did) | DefIdBase::Promoted(did, ..) => Some(did),
299            _ => None,
300        }
301    }
302    pub fn promoted_id(&self) -> Option<PromotedId> {
303        match self.base {
304            DefIdBase::Promoted(_, promoted) => Some(promoted),
305            _ => None,
306        }
307    }
308    /// Returns the [`SyntheticItem`] encoded by this hax [`DefId`], if any.
309    pub fn as_synthetic<'tcx>(&self, _s: &impl BaseState<'tcx>) -> Option<SyntheticItem> {
310        match self.base {
311            DefIdBase::Synthetic(v) => Some(v),
312            _ => None,
313        }
314    }
315
316    pub fn is_local(&self) -> bool {
317        match self.base {
318            DefIdBase::Real(did) | DefIdBase::Promoted(did, ..) => did.is_local(),
319            DefIdBase::ImplAssocItem(id) => id.trait_impl_id.is_local(),
320            DefIdBase::Synthetic(..) => false,
321        }
322    }
323    pub fn is_typeck_child<'tcx>(&self, s: &impl BaseState<'tcx>) -> bool {
324        match self.base {
325            DefIdBase::Real(did) => s.base().tcx.is_typeck_child(did),
326            _ => false,
327        }
328    }
329
330    fn make<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> Self {
331        let base = DefIdBase::Real(def_id);
332        let tcx = s.base().tcx;
333        let contents = DefIdContents {
334            base,
335            kind: get_def_kind(tcx, def_id).sinto(s),
336        };
337        contents.make_def_id(s)
338    }
339
340    pub fn make_synthetic<'tcx, S: BaseState<'tcx>>(s: &S, synthetic: SyntheticItem) -> Self {
341        let contents = DefIdContents {
342            base: DefIdBase::Synthetic(synthetic),
343            kind: DefKind::Struct,
344        };
345        contents.make_def_id(s)
346    }
347
348    /// Construct a hax `DefId` for the nth promoted constant of the current item. That `DefId` has
349    /// no corresponding rustc `DefId`.
350    pub fn make_promoted_child<'tcx, S: BaseState<'tcx>>(
351        &self,
352        s: &S,
353        promoted_id: PromotedId,
354    ) -> Self {
355        let contents = DefIdContents {
356            base: DefIdBase::Promoted(self.real_rust_def_id(), promoted_id),
357            kind: DefKind::PromotedConst,
358        };
359        contents.make_def_id(s)
360    }
361
362    pub fn make_assoc_item_impl<'tcx, S: BaseState<'tcx>>(
363        s: &S,
364        vitem: VirtualImplAssocItem,
365    ) -> Self {
366        let tcx = s.base().tcx;
367        let contents = DefIdContents {
368            base: DefIdBase::ImplAssocItem(vitem),
369            kind: get_def_kind(tcx, vitem.item_decl_id).sinto(s),
370        };
371        contents.make_def_id(s)
372    }
373}
374
375impl DefId {
376    fn crate_name_and_disambig<'tcx>(&self, s: &impl BaseState<'tcx>) -> (Symbol, u32) {
377        let tcx = s.base().tcx;
378        match self.base {
379            DefIdBase::Real(def_id)
380            | DefIdBase::Promoted(def_id, ..)
381            | DefIdBase::ImplAssocItem(VirtualImplAssocItem {
382                trait_impl_id: def_id,
383                ..
384            }) => s.with_global_cache(|cache| cache.crate_name(tcx, def_id.krate)),
385            DefIdBase::Synthetic(..) => (Symbol::intern(SYNTHETIC_CRATE_NAME), 0),
386        }
387    }
388
389    pub fn crate_name<'tcx>(&self, s: &impl BaseState<'tcx>) -> Symbol {
390        self.crate_name_and_disambig(s).0
391    }
392
393    /// Get the span of the definition of this item. This is the span used in diagnostics when
394    /// referring to the item.
395    pub fn def_span<'tcx>(&self, s: &impl BaseState<'tcx>) -> Span {
396        use DefKind::*;
397        let tcx = s.base().tcx;
398        match self.base {
399            DefIdBase::Real(def_id) | DefIdBase::Promoted(def_id, ..) => {
400                if let ForeignMod = &self.kind {
401                    // This kind causes `def_span` to panic.
402                    rustc_span::DUMMY_SP
403                } else if let Some(ldid) = def_id.as_local()
404                    && let hir_id = tcx.local_def_id_to_hir_id(ldid)
405                    && matches!(tcx.hir_node(hir_id), rustc_hir::Node::Synthetic)
406                {
407                    // This kind causes `def_span` to panic.
408                    rustc_span::DUMMY_SP
409                } else {
410                    tcx.def_span(def_id)
411                }
412            }
413            DefIdBase::ImplAssocItem(id) => tcx.def_span(id.item_impl_id),
414            DefIdBase::Synthetic(..) => rustc_span::DUMMY_SP,
415        }
416        .sinto(s)
417    }
418
419    /// The `PathItem` corresponding to this item.
420    pub fn path_item<'tcx>(&self, s: &impl BaseState<'tcx>) -> DisambiguatedDefPathItem {
421        match self.base {
422            DefIdBase::Real(def_id) => {
423                let tcx = s.base().tcx;
424                // Set the def_id so the `CrateRoot` path item can fetch the crate name.
425                let s = &s.with_hax_owner(self);
426                tcx.def_path(def_id)
427                    .data
428                    .last()
429                    .map(|x| x.sinto(s))
430                    .unwrap_or_else(|| {
431                        let (name, disambiguator) = self.crate_name_and_disambig(s);
432                        DisambiguatedDefPathItem {
433                            disambiguator,
434                            data: DefPathItem::CrateRoot { name },
435                        }
436                    })
437            }
438            DefIdBase::Promoted(_, id) => DisambiguatedDefPathItem {
439                data: DefPathItem::PromotedConst,
440                // Reuse the promoted id as disambiguator, like for inline consts.
441                disambiguator: id.as_u32(),
442            },
443            DefIdBase::ImplAssocItem(id) => {
444                let s = &s.with_hax_owner(self);
445                s.base()
446                    .tcx
447                    .def_path(id.item_decl_id)
448                    .data
449                    .last()
450                    .map(|x| x.sinto(s))
451                    .unwrap()
452            }
453            DefIdBase::Synthetic(synthetic) => DisambiguatedDefPathItem {
454                disambiguator: 0,
455                data: DefPathItem::TypeNs(Symbol::intern(&synthetic.name())),
456            },
457        }
458    }
459
460    pub fn parent<'tcx>(&self, s: &impl BaseState<'tcx>) -> Option<DefId> {
461        match self.base {
462            DefIdBase::Real(def_id) => s.tcx().opt_parent(def_id),
463            DefIdBase::Promoted(def_id, _) => Some(def_id),
464            DefIdBase::ImplAssocItem(id) => Some(id.trait_impl_id),
465            DefIdBase::Synthetic(..) => Some(rustc_span::def_id::CRATE_DEF_ID.to_def_id()),
466        }
467        .sinto(s)
468    }
469}
470
471impl DefId {
472    pub fn can_have_generics<'tcx>(&self, s: &impl BaseState<'tcx>) -> bool {
473        let tcx = s.base().tcx;
474        match self.base {
475            DefIdBase::Real(def_id)
476            | DefIdBase::Promoted(def_id, ..)
477            | DefIdBase::ImplAssocItem(VirtualImplAssocItem {
478                item_decl_id: def_id,
479                ..
480            }) => can_have_generics(tcx, def_id),
481            DefIdBase::Synthetic(synthetic) => synthetic.can_have_generics(s),
482        }
483    }
484
485    pub fn generics_of<'tcx>(&self, s: &impl BaseState<'tcx>) -> &'tcx ty::Generics {
486        let tcx = s.base().tcx;
487        match self.base {
488            DefIdBase::Real(def_id) => tcx.generics_of(def_id),
489            DefIdBase::Synthetic(synthetic) => synthetic.generics_of(s),
490            DefIdBase::Promoted(def_id, ..) => s.with_item_cache(self, |cache| {
491                if let Some(generics) = cache.virtual_generics {
492                    return generics;
493                }
494                let generics = Box::leak(Box::new(ty::Generics {
495                    parent: Some(def_id),
496                    parent_count: tcx.generics_of(def_id).count(),
497                    own_params: Default::default(),
498                    param_def_id_to_index: Default::default(),
499                    has_self: false,
500                    has_late_bound_regions: None,
501                }));
502                cache.virtual_generics = Some(generics);
503                generics
504            }),
505            DefIdBase::ImplAssocItem(id) => s.with_item_cache(self, |cache| {
506                if let Some(generics) = cache.virtual_generics {
507                    return generics;
508                }
509                // We build a custom environment here.
510                let item_id = id.item_impl_id;
511                let decl_generics = tcx.generics_of(item_id);
512                let parent_count = tcx.generics_of(id.trait_impl_id).count();
513                let own_params = tcx
514                    .generics_of(id.item_decl_id)
515                    .own_params
516                    .iter()
517                    .cloned()
518                    .enumerate()
519                    .map(|(i, mut param)| {
520                        param.index = parent_count as u32 + i as u32;
521                        param
522                    })
523                    .collect_vec();
524                let param_def_id_to_index = own_params
525                    .iter()
526                    .map(|param| (param.def_id, param.index))
527                    .collect();
528                let generics = Box::leak(Box::new(ty::Generics {
529                    parent: Some(id.trait_impl_id),
530                    parent_count,
531                    own_params,
532                    param_def_id_to_index,
533                    has_self: decl_generics.has_self,
534                    has_late_bound_regions: decl_generics.has_late_bound_regions,
535                }));
536                cache.virtual_generics = Some(generics);
537                generics
538            }),
539        }
540    }
541
542    pub fn identity_args<'tcx>(&self, s: &impl BaseState<'tcx>) -> ty::GenericArgsRef<'tcx> {
543        let tcx = s.base().tcx;
544        match self.base {
545            DefIdBase::Real(def_id) | DefIdBase::Promoted(def_id, ..) => {
546                if can_have_generics(tcx, def_id) {
547                    ty::GenericArgs::identity_for_item(tcx, def_id)
548                } else {
549                    ty::GenericArgsRef::default()
550                }
551            }
552            DefIdBase::Synthetic(synthetic) => synthetic.identity_args(s),
553            DefIdBase::ImplAssocItem(_) => panic!(
554                "virtual trait impl associated items do not have a \
555                sensible `identity_args`. consider `identity_args_for_item_decl`"
556            ),
557        }
558    }
559
560    pub fn param_env<'tcx>(&self, s: &impl BaseState<'tcx>) -> ty::ParamEnv<'tcx> {
561        let tcx = s.base().tcx;
562        match self.base {
563            DefIdBase::ImplAssocItem(id) => {
564                let item_args = id.identity_args_for_item_decl(s);
565                let impl_predicates = tcx.param_env(id.trait_impl_id).caller_bounds().iter();
566                let item_predicates = tcx
567                    .clauses_of(id.item_decl_id)
568                    .instantiate_own(tcx, item_args)
569                    .map(|(predicate, _)| predicate.skip_normalization());
570                param_env_from_clauses(tcx, impl_predicates.chain(item_predicates))
571            }
572            DefIdBase::Real(def_id) | DefIdBase::Promoted(def_id, ..) => {
573                if can_have_generics(tcx, def_id) {
574                    tcx.param_env(def_id)
575                } else {
576                    ty::ParamEnv::empty()
577                }
578            }
579            DefIdBase::Synthetic(synthetic) => synthetic.param_env(s),
580        }
581    }
582
583    pub fn typing_env<'tcx>(&self, s: &impl BaseState<'tcx>) -> ty::TypingEnv<'tcx> {
584        ty::TypingEnv::new(self.param_env(s), ty::TypingMode::PostAnalysis)
585    }
586
587    pub fn required_predicates<'tcx, S: BaseState<'tcx>>(
588        &self,
589        s: &S,
590    ) -> ItemPredicates<'tcx, Self> {
591        let state = s.base_state();
592        ItemPredicates::required(s.base().elab_ctx, &state, self.clone())
593    }
594
595    pub fn type_of<'tcx, S: BaseState<'tcx>>(&self, s: &S) -> ty::EarlyBinder<'tcx, ty::Ty<'tcx>> {
596        let tcx: ty::TyCtxt<'tcx> = s.base().tcx;
597        match self.base {
598            DefIdBase::Real(def_id) | DefIdBase::Promoted(def_id, ..) => tcx.type_of(def_id),
599            DefIdBase::Synthetic(synthetic) => synthetic.type_of(s),
600            DefIdBase::ImplAssocItem(id) => tcx.type_of(id.item_decl_id),
601        }
602    }
603}
604
605impl DefId {
606    /// Gets the visibility (`pub` or not) of the definition. Returns `None` for defs that don't have a
607    /// meaningful visibility.
608    pub fn visibility<'tcx>(&self, tcx: ty::TyCtxt<'tcx>) -> Option<bool> {
609        use DefKind::*;
610        match self.kind {
611            AssocConst { .. }
612            | AssocFn
613            | Const { .. }
614            | Enum
615            | Field
616            | Fn
617            | ForeignTy
618            | Macro { .. }
619            | Mod
620            | Static { .. }
621            | Struct
622            | Trait
623            | TraitAlias
624            | TyAlias { .. }
625            | Union
626            | Use
627            | Variant => {
628                let def_id = self.as_real_def_id()?;
629                Some(tcx.visibility(def_id).is_public())
630            }
631            // These kinds don't have visibility modifiers (which would cause `visibility` to panic).
632            AnonConst
633            | AssocTy
634            | Closure
635            | ConstParam
636            | Ctor { .. }
637            | ExternCrate
638            | ForeignMod
639            | GlobalAsm
640            | Impl { .. }
641            | PromotedConst
642            | LifetimeParam
643            | OpaqueTy
644            | SyntheticCoroutineBody
645            | TyParam => None,
646        }
647    }
648
649    /// Gets the attributes of the definition.
650    pub fn attrs<'tcx>(&self, tcx: ty::TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute] {
651        use DefKind::*;
652        match self.kind {
653            // These kinds cause `get_attrs` to panic.
654            ConstParam | LifetimeParam | TyParam | ForeignMod => &[],
655            _ => {
656                if let Some(def_id) = self.as_real_def_id() {
657                    if let Some(ldid) = def_id.as_local() {
658                        tcx.hir_attrs(tcx.local_def_id_to_hir_id(ldid))
659                    } else if matches!(self.kind, AnonConst) {
660                        // Rustc doesn't store the attributes of anonymous constants in crate
661                        // metadata; asking for them panics.
662                        &[]
663                    } else {
664                        tcx.attrs_for_def(def_id)
665                    }
666                } else {
667                    &[]
668                }
669            }
670        }
671    }
672}
673
674impl std::ops::Deref for DefId {
675    type Target = DefIdContents;
676    fn deref(&self) -> &Self::Target {
677        &self.contents
678    }
679}
680
681impl std::fmt::Debug for DefId {
682    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
683        match self.base {
684            DefIdBase::Real(def_id) => write!(f, "{def_id:?}"),
685            DefIdBase::Promoted(def_id, promoted) => {
686                write!(f, "{def_id:?}::promoted#{}", promoted.as_u32())
687            }
688            DefIdBase::Synthetic(item) => write!(f, "{}", item.name()),
689            DefIdBase::ImplAssocItem(id) => {
690                write!(f, "{:?}::{:?}", id.trait_impl_id, id.item_decl_id)
691            }
692        }
693    }
694}
695
696impl std::hash::Hash for DefId {
697    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
698        self.base.hash(state);
699    }
700}
701
702/// Gets the kind of the definition. Can't use `def_kind` directly because this crashes on the
703/// crate root.
704pub(crate) fn get_def_kind<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> hir::def::DefKind {
705    if def_id == rustc_span::def_id::CRATE_DEF_ID.to_def_id() {
706        // Horrible hack: without this, `def_kind` crashes on the crate root. Presumably some table
707        // isn't properly initialized otherwise.
708        let _ = tcx.def_span(def_id);
709    };
710    tcx.def_kind(def_id)
711}
712
713impl<'s, S: BaseState<'s>> SInto<S, DefId> for RDefId {
714    fn sinto(&self, s: &S) -> DefId {
715        if let Some(def_id) = s.with_global_cache(|cache| cache.def_ids.get(self).cloned()) {
716            return def_id;
717        }
718        let def_id = DefId::make(s, *self);
719        s.with_global_cache(|cache| {
720            cache.def_ids.insert(*self, def_id.clone());
721        });
722        def_id
723    }
724}
725
726impl<S> SInto<S, DefId> for DefId {
727    fn sinto(&self, _s: &S) -> DefId {
728        self.clone()
729    }
730}
731
732/// Reflects [`rustc_hir::definitions::DefPathData`]
733
734#[derive(Clone, Debug, Hash, PartialEq, Eq, AdtInto)]
735#[args(<'ctx, S: UnderOwnerState<'ctx>>, from: rustc_hir::definitions::DefPathData, state: S as s)]
736pub enum DefPathItem {
737    CrateRoot {
738        #[value(s.owner().crate_name(s))]
739        name: Symbol,
740    },
741    Impl,
742    ForeignMod,
743    Use,
744    GlobalAsm,
745    TypeNs(Symbol),
746    ValueNs(Symbol),
747    MacroNs(Symbol),
748    LifetimeNs(Symbol),
749    Closure,
750    Ctor,
751    AnonConst,
752    #[disable_mapping]
753    PromotedConst,
754    OpaqueTy,
755    OpaqueLifetime(Symbol),
756    AnonAssocTy(Symbol),
757    SyntheticCoroutineBody,
758    NestedStatic,
759}
760
761#[derive(Clone, Debug, Hash, PartialEq, Eq, AdtInto)]
762#[args(<'a, S: UnderOwnerState<'a>>, from: rustc_hir::definitions::DisambiguatedDefPathData, state: S as s)]
763/// Reflects [`rustc_hir::definitions::DisambiguatedDefPathData`]
764pub struct DisambiguatedDefPathItem {
765    pub data: DefPathItem,
766    pub disambiguator: u32,
767}