Skip to main content

rustdoc/clean/
types.rs

1use std::fmt::Write;
2use std::hash::Hash;
3use std::path::PathBuf;
4use std::sync::{Arc, OnceLock as OnceCell};
5use std::{fmt, iter};
6
7use arrayvec::ArrayVec;
8use itertools::Either;
9use rustc_abi::{ExternAbi, VariantIdx};
10use rustc_ast as ast;
11use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
12use rustc_data_structures::thin_vec::ThinVec;
13use rustc_hir as hir;
14use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation, DocAttribute};
15use rustc_hir::def::{CtorKind, DefKind, Res};
16use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
17use rustc_hir::lang_items::LangItem;
18use rustc_hir::{Attribute, BodyId, ConstStability, Mutability, Stability, StableSince, find_attr};
19use rustc_index::IndexVec;
20use rustc_metadata::rendered_const;
21use rustc_middle::span_bug;
22use rustc_middle::ty::fast_reject::SimplifiedType;
23use rustc_middle::ty::{self, TyCtxt, Visibility};
24use rustc_resolve::rustdoc::{
25    DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments,
26};
27use rustc_session::Session;
28use rustc_span::hygiene::MacroKind;
29use rustc_span::symbol::{Symbol, kw, sym};
30use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents};
31use tracing::{debug, trace};
32
33pub(crate) use self::ItemKind::*;
34pub(crate) use self::Type::{
35    Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
36    RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
37};
38use crate::clean::cfg::Cfg;
39use crate::clean::clean_middle_path;
40use crate::clean::inline::{self, print_inlined_const};
41use crate::clean::utils::{is_literal_expr, print_evaluated_const};
42use crate::core::DocContext;
43use crate::formats::cache::Cache;
44use crate::formats::item_type::ItemType;
45use crate::html::format::HrefInfo;
46use crate::html::render::Context;
47use crate::passes::collect_intra_doc_links::UrlFragment;
48
49#[cfg(test)]
50mod tests;
51
52pub(crate) type ItemIdSet = FxHashSet<ItemId>;
53
54#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
55pub(crate) enum ItemId {
56    /// A "normal" item that uses a [`DefId`] for identification.
57    DefId(DefId),
58    /// Identifier that is used for auto traits.
59    Auto { trait_: DefId, for_: DefId },
60    /// Identifier that is used for blanket implementations.
61    Blanket { impl_id: DefId, for_: DefId },
62}
63
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub(crate) enum Defaultness {
66    Implicit,
67    Default,
68    Final,
69}
70
71impl Defaultness {
72    pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
73        match defaultness {
74            hir::Defaultness::Default { .. } => Self::Implicit,
75            hir::Defaultness::Final => Self::Final,
76        }
77    }
78
79    pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
80        match defaultness {
81            hir::Defaultness::Default { .. } => Self::Default,
82            hir::Defaultness::Final => Self::Implicit,
83        }
84    }
85}
86
87impl ItemId {
88    #[inline]
89    pub(crate) fn is_local(self) -> bool {
90        match self {
91            ItemId::Auto { for_: id, .. }
92            | ItemId::Blanket { for_: id, .. }
93            | ItemId::DefId(id) => id.is_local(),
94        }
95    }
96
97    #[inline]
98    #[track_caller]
99    pub(crate) fn expect_def_id(self) -> DefId {
100        self.as_def_id()
101            .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
102    }
103
104    #[inline]
105    pub(crate) fn as_def_id(self) -> Option<DefId> {
106        match self {
107            ItemId::DefId(id) => Some(id),
108            _ => None,
109        }
110    }
111
112    #[inline]
113    pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
114        self.as_def_id().and_then(|id| id.as_local())
115    }
116
117    #[inline]
118    pub(crate) fn krate(self) -> CrateNum {
119        match self {
120            ItemId::Auto { for_: id, .. }
121            | ItemId::Blanket { for_: id, .. }
122            | ItemId::DefId(id) => id.krate,
123        }
124    }
125}
126
127impl From<DefId> for ItemId {
128    fn from(id: DefId) -> Self {
129        Self::DefId(id)
130    }
131}
132
133/// The crate currently being documented.
134#[derive(Debug)]
135pub(crate) struct Crate {
136    pub(crate) module: Item,
137    /// Only here so that they can be filtered through the rustdoc passes.
138    pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
139}
140
141impl Crate {
142    pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
143        ExternalCrate::LOCAL.name(tcx)
144    }
145
146    pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
147        ExternalCrate::LOCAL.src(tcx)
148    }
149}
150
151#[derive(Copy, Clone, Debug)]
152pub(crate) struct ExternalCrate {
153    pub(crate) crate_num: CrateNum,
154}
155
156impl ExternalCrate {
157    const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
158
159    #[inline]
160    pub(crate) fn def_id(&self) -> DefId {
161        self.crate_num.as_def_id()
162    }
163
164    pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
165        let krate_span = tcx.def_span(self.def_id());
166        tcx.sess.source_map().span_to_filename(krate_span)
167    }
168
169    pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
170        tcx.crate_name(self.crate_num)
171    }
172
173    pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
174        match self.src(tcx) {
175            FileName::Real(ref p) => {
176                match p
177                    .local_path()
178                    .or(Some(p.path(RemapPathScopeComponents::DOCUMENTATION)))
179                    .unwrap()
180                    .parent()
181                {
182                    Some(p) => p.to_path_buf(),
183                    None => PathBuf::new(),
184                }
185            }
186            _ => PathBuf::new(),
187        }
188    }
189
190    /// Attempts to find where an external crate is located, given that we're
191    /// rendering into the specified source destination.
192    pub(crate) fn location(
193        &self,
194        extern_url: Option<&str>,
195        extern_url_takes_precedence: bool,
196        dst: &std::path::Path,
197        tcx: TyCtxt<'_>,
198    ) -> ExternalLocation {
199        use ExternalLocation::*;
200
201        fn to_remote(url: impl ToString) -> ExternalLocation {
202            let mut url = url.to_string();
203            if !url.ends_with('/') {
204                url.push('/');
205            }
206            let is_absolute = url.starts_with('/')
207                || url.split_once(':').is_some_and(|(scheme, _)| {
208                    scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic())
209                        && scheme
210                            .bytes()
211                            .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'))
212                });
213            Remote { url, is_absolute }
214        }
215
216        // See if there's documentation generated into the local directory
217        // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
218        // Make sure to call `location()` by that time.
219        let local_location = dst.join(self.name(tcx).as_str());
220        if local_location.is_dir() {
221            return Local;
222        }
223
224        if extern_url_takes_precedence && let Some(url) = extern_url {
225            return to_remote(url);
226        }
227
228        // Failing that, see if there's an attribute specifying where to find this
229        // external crate
230        let did = self.crate_num.as_def_id();
231        find_attr!(tcx, did, Doc(d) =>d.html_root_url.map(|(url, _)| url))
232            .flatten()
233            .map(to_remote)
234            .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
235            .unwrap_or(Unknown) // Well, at least we tried.
236    }
237
238    fn mapped_root_modules<T>(
239        &self,
240        tcx: TyCtxt<'_>,
241        f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>,
242    ) -> impl Iterator<Item = (DefId, T)> {
243        let root = self.def_id();
244
245        if root.is_local() {
246            Either::Left(
247                tcx.hir_root_module()
248                    .item_ids
249                    .iter()
250                    .filter(move |&&id| matches!(tcx.hir_item(id).kind, hir::ItemKind::Mod(..)))
251                    .filter_map(move |&id| f(id.owner_id.into(), tcx)),
252            )
253        } else {
254            Either::Right(
255                tcx.module_children(root)
256                    .iter()
257                    .filter_map(|item| {
258                        if let Res::Def(DefKind::Mod, did) = item.res { Some(did) } else { None }
259                    })
260                    .filter_map(move |did| f(did, tcx)),
261            )
262        }
263    }
264
265    pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = (DefId, Symbol)> {
266        self.retrieve_keywords_or_documented_attributes(tcx, |d| d.keyword.map(|(v, _)| v))
267    }
268    pub(crate) fn documented_attributes(
269        &self,
270        tcx: TyCtxt<'_>,
271    ) -> impl Iterator<Item = (DefId, Symbol)> {
272        self.retrieve_keywords_or_documented_attributes(tcx, |d| d.attribute.map(|(v, _)| v))
273    }
274
275    fn retrieve_keywords_or_documented_attributes<F: Fn(&DocAttribute) -> Option<Symbol>>(
276        &self,
277        tcx: TyCtxt<'_>,
278        callback: F,
279    ) -> impl Iterator<Item = (DefId, Symbol)> {
280        let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> {
281            find_attr!(tcx, did, Doc(d) => callback(d)).flatten().map(|value| (did, value))
282        };
283        self.mapped_root_modules(tcx, as_target)
284    }
285
286    pub(crate) fn primitives(
287        &self,
288        tcx: TyCtxt<'_>,
289    ) -> impl Iterator<Item = (DefId, PrimitiveType)> {
290        // Collect all inner modules which are tagged as implementations of
291        // primitives.
292        //
293        // Note that this loop only searches the top-level items of the crate,
294        // and this is intentional. If we were to search the entire crate for an
295        // item tagged with `#[rustc_doc_primitive]` then we would also have to
296        // search the entirety of external modules for items tagged
297        // `#[rustc_doc_primitive]`, which is a pretty inefficient process (decoding
298        // all that metadata unconditionally).
299        //
300        // In order to keep the metadata load under control, the
301        // `#[rustc_doc_primitive]` feature is explicitly designed to only allow the
302        // primitive tags to show up as the top level items in a crate.
303        //
304        // Also note that this does not attempt to deal with modules tagged
305        // duplicately for the same primitive. This is handled later on when
306        // rendering by delegating everything to a hash map.
307        fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
308            let (attr_span, prim_sym) = find_attr!(
309                tcx, def_id,
310                RustcDocPrimitive(span, prim) => (*span, *prim)
311            )?;
312            let Some(prim) = PrimitiveType::from_symbol(prim_sym) else {
313                span_bug!(attr_span, "primitive `{prim_sym}` is not a member of `PrimitiveType`");
314            };
315            Some((def_id, prim))
316        }
317
318        self.mapped_root_modules(tcx, as_primitive)
319    }
320}
321
322/// Indicates where an external crate can be found.
323#[derive(Debug)]
324pub(crate) enum ExternalLocation {
325    /// Remote URL root of the external crate
326    Remote { url: String, is_absolute: bool },
327    /// This external crate can be found in the local doc/ folder
328    Local,
329    /// The external crate could not be found.
330    Unknown,
331}
332
333/// Anything with a source location and set of attributes and, optionally, a
334/// name. That is, anything that can be documented. This doesn't correspond
335/// directly to the AST's concept of an item; it's a strict superset.
336#[derive(Clone)]
337pub(crate) struct Item {
338    pub(crate) inner: Box<ItemInner>,
339}
340
341// Why does the `Item`/`ItemInner` split exist? `Vec<Item>`s are common, and
342// without the split `Item` would be a large type (100+ bytes) which results in
343// lots of wasted space in the unused parts of a `Vec<Item>`. With the split,
344// `Item` is just 8 bytes, and the wasted space is avoided, at the cost of an
345// extra allocation per item. This is a performance win.
346#[derive(Clone)]
347pub(crate) struct ItemInner {
348    /// The name of this item.
349    /// Optional because not every item has a name, e.g. impls.
350    pub(crate) name: Option<Symbol>,
351    /// Information about this item that is specific to what kind of item it is.
352    /// E.g., struct vs enum vs function.
353    pub(crate) kind: ItemKind,
354    pub(crate) attrs: Attributes,
355    /// The effective stability, filled out by the `propagate-stability` pass.
356    pub(crate) stability: Option<Stability>,
357    pub(crate) item_id: ItemId,
358    /// This is the `LocalDefId` of the `use` statement if the item was inlined.
359    /// The crate metadata doesn't hold this information, so the `use` statement
360    /// always belongs to the current crate.
361    pub(crate) inline_stmt_id: Option<LocalDefId>,
362    pub(crate) cfg: Option<Arc<Cfg>>,
363}
364
365impl std::ops::Deref for Item {
366    type Target = ItemInner;
367    fn deref(&self) -> &ItemInner {
368        &self.inner
369    }
370}
371
372/// NOTE: this does NOT unconditionally print every item, to avoid thousands of lines of logs.
373/// If you want to see the debug output for attributes and the `kind` as well, use `{:#?}` instead of `{:?}`.
374impl fmt::Debug for Item {
375    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376        let alternate = f.alternate();
377        // hand-picked fields that don't bloat the logs too much
378        let mut fmt = f.debug_struct("Item");
379        fmt.field("name", &self.name).field("item_id", &self.item_id);
380        // allow printing the full item if someone really wants to
381        if alternate {
382            fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
383        } else {
384            fmt.field("kind", &self.type_());
385            fmt.field("docs", &self.doc_value());
386        }
387        fmt.finish()
388    }
389}
390
391pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
392    Span::new(def_id.as_local().map_or_else(
393        || tcx.def_span(def_id),
394        |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
395    ))
396}
397
398fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
399    let parent = tcx.parent(def_id);
400    match tcx.def_kind(parent) {
401        DefKind::Struct | DefKind::Union => false,
402        DefKind::Variant => true,
403        parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
404    }
405}
406
407impl Item {
408    /// Returns the effective stability of the item.
409    ///
410    /// This method should only be called after the `propagate-stability` pass has been run.
411    pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
412        let stability = self.inner.stability;
413        debug_assert!(
414            stability.is_some()
415                || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
416            "missing stability for cleaned item: {self:?}",
417        );
418        stability
419    }
420
421    pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
422        self.def_id().and_then(|did| tcx.lookup_const_stability(did))
423    }
424
425    pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
426        self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
427            // `allowed_through_unstable_modules` is a bug-compatibility hack for old rustc
428            // versions; the paths that are exposed through it are "deprecated" because they
429            // were never supposed to work at all.
430            let stab = self.stability(tcx)?;
431            if let rustc_hir::StabilityLevel::Stable {
432                allowed_through_unstable_modules: Some(note),
433                ..
434            } = stab.level
435            {
436                Some(Deprecation {
437                    since: DeprecatedSince::Unspecified,
438                    note: Some(Ident { name: note, span: DUMMY_SP }),
439                    suggestion: None,
440                })
441            } else {
442                None
443            }
444        })
445    }
446
447    pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
448        self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect())
449    }
450
451    pub(crate) fn is_unstable(&self) -> bool {
452        self.stability.is_some_and(|x| x.is_unstable())
453    }
454
455    pub(crate) fn is_exported_macro(&self) -> bool {
456        match self.kind {
457            ItemKind::MacroItem(..) => find_attr!(&self.attrs.other_attrs, MacroExport { .. }),
458            _ => false,
459        }
460    }
461
462    pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
463        self.item_id
464            .as_def_id()
465            .map(|did| {
466                inner_docs(
467                    #[allow(deprecated)]
468                    tcx.get_all_attrs(did),
469                )
470            })
471            .unwrap_or(false)
472    }
473
474    /// Returns true if item is an associated function with a `self` parameter.
475    pub(crate) fn has_self_param(&self) -> bool {
476        if let ItemKind::MethodItem(box Function { decl, .. }, _) = &self.inner.kind {
477            decl.receiver_type().is_some()
478        } else {
479            false
480        }
481    }
482
483    pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
484        let kind = match &self.kind {
485            ItemKind::StrippedItem(k) => k,
486            _ => &self.kind,
487        };
488        match kind {
489            ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
490            ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
491            ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
492                if let ItemId::Blanket { impl_id, .. } = self.item_id {
493                    Some(rustc_span(impl_id, tcx))
494                } else {
495                    panic!("blanket impl item has non-blanket ID")
496                }
497            }
498            _ => self.def_id().map(|did| rustc_span(did, tcx)),
499        }
500    }
501
502    pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
503        let deprecation_notes = find_attr!(&self.attrs.other_attrs, Deprecated { deprecation, .. } => deprecation.note.map(|note| note.span)).flatten();
504
505        span_of_fragments(&self.attrs.doc_strings)
506            .into_iter()
507            .chain(deprecation_notes)
508            .reduce(|a, b| a.to(b))
509            .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
510    }
511
512    /// Combine all doc strings into a single value handling indentation and newlines as needed.
513    pub(crate) fn doc_value(&self) -> String {
514        self.attrs.doc_value()
515    }
516
517    /// Combine all doc strings into a single value handling indentation and newlines as needed.
518    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
519    /// documentation but it is empty (e.g. `#[doc = ""]`).
520    pub(crate) fn opt_doc_value(&self) -> Option<String> {
521        self.attrs.opt_doc_value()
522    }
523
524    pub(crate) fn from_def_id_and_parts(
525        def_id: DefId,
526        name: Option<Symbol>,
527        kind: ItemKind,
528        tcx: TyCtxt<'_>,
529    ) -> Item {
530        #[allow(deprecated)]
531        let hir_attrs = tcx.get_all_attrs(def_id);
532
533        Self::from_def_id_and_attrs_and_parts(
534            def_id,
535            name,
536            kind,
537            Attributes::from_hir(hir_attrs),
538            None,
539        )
540    }
541
542    pub(crate) fn from_def_id_and_attrs_and_parts(
543        def_id: DefId,
544        name: Option<Symbol>,
545        kind: ItemKind,
546        attrs: Attributes,
547        cfg: Option<Arc<Cfg>>,
548    ) -> Item {
549        trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
550
551        Item {
552            inner: Box::new(ItemInner {
553                item_id: def_id.into(),
554                kind,
555                attrs,
556                stability: None,
557                name,
558                cfg,
559                inline_stmt_id: None,
560            }),
561        }
562    }
563
564    /// If the item has doc comments from a reexport, returns the item id of that reexport,
565    /// otherwise returns returns the item id.
566    ///
567    /// This is used as a key for caching intra-doc link resolution,
568    /// to prevent two reexports of the same item from using the same cache.
569    pub(crate) fn item_or_reexport_id(&self) -> ItemId {
570        // added documentation on a reexport is always prepended.
571        self.attrs
572            .doc_strings
573            .first()
574            .map(|x| x.item_id)
575            .flatten()
576            .map(ItemId::from)
577            .unwrap_or(self.item_id)
578    }
579
580    pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
581        use crate::html::format::{href, link_tooltip};
582
583        let Some(links) = cx.cache().intra_doc_links.get(&self.item_or_reexport_id()) else {
584            return vec![];
585        };
586        links
587            .iter()
588            .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
589                debug!(?id);
590                if let Ok(HrefInfo { mut url, .. }) = href(*id, cx) {
591                    debug!(?url);
592                    match fragment {
593                        Some(UrlFragment::Item(def_id)) => {
594                            write!(url, "{}", crate::html::format::fragment(*def_id, cx.tcx()))
595                                .unwrap();
596                        }
597                        Some(UrlFragment::UserWritten(raw)) => {
598                            url.push('#');
599                            url.push_str(raw);
600                        }
601                        None => {}
602                    }
603                    Some(RenderedLink {
604                        original_text: s.clone(),
605                        new_text: link_text.clone(),
606                        tooltip: link_tooltip(*id, fragment, cx).to_string(),
607                        href: url,
608                    })
609                } else {
610                    None
611                }
612            })
613            .collect()
614    }
615
616    /// Find a list of all link names, without finding their href.
617    ///
618    /// This is used for generating summary text, which does not include
619    /// the link text, but does need to know which `[]`-bracketed names
620    /// are actually links.
621    pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
622        let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
623            return vec![];
624        };
625        links
626            .iter()
627            .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
628                original_text: s.clone(),
629                new_text: link_text.clone(),
630                href: String::new(),
631                tooltip: String::new(),
632            })
633            .collect()
634    }
635
636    pub(crate) fn is_crate(&self) -> bool {
637        self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
638    }
639    pub(crate) fn is_mod(&self) -> bool {
640        self.type_() == ItemType::Module
641    }
642    pub(crate) fn is_struct(&self) -> bool {
643        self.type_() == ItemType::Struct
644    }
645    pub(crate) fn is_enum(&self) -> bool {
646        self.type_() == ItemType::Enum
647    }
648    pub(crate) fn is_variant(&self) -> bool {
649        self.type_() == ItemType::Variant
650    }
651    pub(crate) fn is_associated_type(&self) -> bool {
652        matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
653    }
654    pub(crate) fn is_required_associated_type(&self) -> bool {
655        matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
656    }
657    pub(crate) fn is_associated_const(&self) -> bool {
658        matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
659    }
660    pub(crate) fn is_required_associated_const(&self) -> bool {
661        matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
662    }
663    pub(crate) fn is_method(&self) -> bool {
664        self.type_() == ItemType::Method
665    }
666    pub(crate) fn is_ty_method(&self) -> bool {
667        self.type_() == ItemType::TyMethod
668    }
669    pub(crate) fn is_primitive(&self) -> bool {
670        self.type_() == ItemType::Primitive
671    }
672    pub(crate) fn is_union(&self) -> bool {
673        self.type_() == ItemType::Union
674    }
675    pub(crate) fn is_import(&self) -> bool {
676        self.type_() == ItemType::Import
677    }
678    pub(crate) fn is_extern_crate(&self) -> bool {
679        self.type_() == ItemType::ExternCrate
680    }
681    pub(crate) fn is_keyword(&self) -> bool {
682        self.type_() == ItemType::Keyword
683    }
684    pub(crate) fn is_attribute(&self) -> bool {
685        self.type_() == ItemType::Attribute
686    }
687    /// Returns `true` if the item kind is one of the following:
688    ///
689    /// * `ItemType::Primitive`
690    /// * `ItemType::Keyword`
691    /// * `ItemType::Attribute`
692    ///
693    /// They are considered fake because they only exist thanks to their
694    /// `#[doc(primitive|keyword|attribute)]` attribute.
695    pub(crate) fn is_fake_item(&self) -> bool {
696        matches!(self.type_(), ItemType::Primitive | ItemType::Keyword | ItemType::Attribute)
697    }
698    pub(crate) fn is_stripped(&self) -> bool {
699        match self.kind {
700            StrippedItem(..) => true,
701            ImportItem(ref i) => !i.should_be_displayed,
702            _ => false,
703        }
704    }
705    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
706        match self.kind {
707            StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
708            UnionItem(ref union_) => Some(union_.has_stripped_entries()),
709            EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
710            VariantItem(ref v) => v.has_stripped_entries(),
711            TypeAliasItem(ref type_alias) => {
712                type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
713            }
714            _ => None,
715        }
716    }
717
718    pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
719        self.stability(tcx).as_ref().and_then(|s| {
720            let mut classes = Vec::with_capacity(2);
721
722            if s.is_unstable() {
723                classes.push("unstable");
724            }
725
726            // FIXME: what about non-staged API items that are deprecated?
727            if self.deprecation(tcx).is_some() {
728                classes.push("deprecated");
729            }
730
731            if !classes.is_empty() { Some(classes.join(" ")) } else { None }
732        })
733    }
734
735    pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
736        self.stability(tcx).and_then(|stability| stability.stable_since())
737    }
738
739    pub(crate) fn is_non_exhaustive(&self) -> bool {
740        find_attr!(&self.attrs.other_attrs, NonExhaustive(..))
741    }
742
743    /// Returns a documentation-level item type from the item.
744    pub(crate) fn type_(&self) -> ItemType {
745        ItemType::from(self)
746    }
747
748    pub(crate) fn defaultness(&self) -> Option<Defaultness> {
749        match self.kind {
750            ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => {
751                Some(defaultness)
752            }
753            _ => None,
754        }
755    }
756
757    /// Returns a `FnHeader` if `self` is a function item, otherwise returns `None`.
758    pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
759        fn build_fn_header(
760            def_id: DefId,
761            tcx: TyCtxt<'_>,
762            asyncness: ty::Asyncness,
763        ) -> hir::FnHeader {
764            let sig = tcx.fn_sig(def_id).skip_binder();
765            let constness = if tcx.is_const_fn(def_id) {
766                // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent
767                // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we
768                // won't be printing correct syntax plus the syntax is unstable.
769                if let Some(assoc) = tcx.opt_associated_item(def_id)
770                    && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) =
771                        assoc.container
772                {
773                    hir::Constness::NotConst
774                } else {
775                    hir::Constness::Const
776                }
777            } else {
778                hir::Constness::NotConst
779            };
780            let asyncness = match asyncness {
781                ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
782                ty::Asyncness::No => hir::IsAsync::NotAsync,
783            };
784            hir::FnHeader {
785                safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
786                    hir::HeaderSafety::SafeTargetFeatures
787                } else {
788                    sig.safety().into()
789                },
790                abi: sig.abi(),
791                constness,
792                asyncness,
793            }
794        }
795        let header = match self.kind {
796            ItemKind::ForeignFunctionItem(_, safety) => {
797                let def_id = self.def_id().unwrap();
798                let abi = tcx.fn_sig(def_id).skip_binder().abi();
799                hir::FnHeader {
800                    safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
801                        hir::HeaderSafety::SafeTargetFeatures
802                    } else {
803                        safety.into()
804                    },
805                    abi,
806                    constness: if tcx.is_const_fn(def_id) {
807                        hir::Constness::Const
808                    } else {
809                        hir::Constness::NotConst
810                    },
811                    asyncness: hir::IsAsync::NotAsync,
812                }
813            }
814            ItemKind::FunctionItem(_)
815            | ItemKind::MethodItem(..)
816            | ItemKind::RequiredMethodItem(..) => {
817                let def_id = self.def_id().unwrap();
818                build_fn_header(def_id, tcx, tcx.asyncness(def_id))
819            }
820            _ => return None,
821        };
822        Some(header)
823    }
824
825    /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
826    /// is returned.
827    pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
828        let def_id = match self.item_id {
829            // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
830            ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
831            ItemId::DefId(def_id) => def_id,
832        };
833
834        match self.kind {
835            // Primitives and Keywords are written in the source code as private modules.
836            // The modules need to be private so that nobody actually uses them, but the
837            // keywords and primitives that they are documenting are public.
838            ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
839                return Some(Visibility::Public);
840            }
841            // Variant fields inherit their enum's visibility.
842            StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
843                return None;
844            }
845            // Variants always inherit visibility
846            VariantItem(..) | ImplItem(..) => return None,
847            // Trait items inherit the trait's visibility
848            RequiredAssocConstItem(..)
849            | ProvidedAssocConstItem(..)
850            | ImplAssocConstItem(..)
851            | AssocTypeItem(..)
852            | RequiredAssocTypeItem(..)
853            | RequiredMethodItem(..)
854            | MethodItem(..) => {
855                match tcx.associated_item(def_id).container {
856                    // Trait impl items always inherit the impl's visibility --
857                    // we don't want to show `pub`.
858                    ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
859                        return None;
860                    }
861                    ty::AssocContainer::InherentImpl => {}
862                }
863            }
864            _ => {}
865        }
866        let def_id = match self.inline_stmt_id {
867            Some(inlined) => inlined.to_def_id(),
868            None => def_id,
869        };
870        Some(tcx.visibility(def_id))
871    }
872
873    pub fn is_doc_hidden(&self) -> bool {
874        self.attrs.is_doc_hidden()
875    }
876
877    pub fn def_id(&self) -> Option<DefId> {
878        self.item_id.as_def_id()
879    }
880}
881
882#[derive(Clone, Debug)]
883pub(crate) enum ItemKind {
884    ExternCrateItem {
885        /// The crate's name, *not* the name it's imported as.
886        src: Option<Symbol>,
887    },
888    ImportItem(Import),
889    StructItem(Struct),
890    UnionItem(Union),
891    EnumItem(Enum),
892    FunctionItem(Box<Function>),
893    ModuleItem(Module),
894    TypeAliasItem(Box<TypeAlias>),
895    StaticItem(Static),
896    TraitItem(Box<Trait>),
897    TraitAliasItem(TraitAlias),
898    ImplItem(Box<Impl>),
899    /// This variant is used only as a placeholder for trait impls in order to correctly compute
900    /// `doc_cfg` as trait impls are added to `clean::Crate` after we went through the whole tree.
901    PlaceholderImplItem,
902    /// A required method in a trait declaration meaning it's only a function signature.
903    RequiredMethodItem(Box<Function>, Defaultness),
904    /// A method in a trait impl or a provided method in a trait declaration.
905    ///
906    /// Compared to [RequiredMethodItem], it also contains a method body.
907    MethodItem(Box<Function>, Defaultness),
908    StructFieldItem(Type),
909    VariantItem(Variant),
910    /// `fn`s from an extern block
911    ForeignFunctionItem(Box<Function>, hir::Safety),
912    /// `static`s from an extern block
913    ForeignStaticItem(Static, hir::Safety),
914    /// `type`s from an extern block
915    ForeignTypeItem,
916    MacroItem(Macro),
917    ProcMacroItem(ProcMacro),
918    PrimitiveItem(PrimitiveType),
919    /// A required associated constant in a trait declaration.
920    RequiredAssocConstItem(Generics, Box<Type>),
921    ConstantItem(Box<Constant>),
922    /// An associated constant in a trait declaration with provided default value.
923    ProvidedAssocConstItem(Box<Constant>),
924    /// An associated constant in an inherent impl or trait impl.
925    ImplAssocConstItem(Box<Constant>),
926    /// A required associated type in a trait declaration.
927    ///
928    /// The bounds may be non-empty if there is a `where` clause.
929    RequiredAssocTypeItem(Generics, Vec<GenericBound>),
930    /// An associated type in a trait impl or a provided one in a trait declaration.
931    AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
932    /// An item that has been stripped by a rustdoc pass
933    StrippedItem(Box<ItemKind>),
934    /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used
935    /// to generate documentation for Rust keywords.
936    KeywordItem,
937    /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used
938    /// to generate documentation for Rust builtin attributes.
939    AttributeItem,
940}
941
942impl ItemKind {
943    /// Some items contain others such as structs (for their fields) and Enums
944    /// (for their variants). This method returns those contained items.
945    pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
946        match self {
947            StructItem(s) => s.fields.iter(),
948            UnionItem(u) => u.fields.iter(),
949            VariantItem(v) => match &v.kind {
950                VariantKind::CLike => [].iter(),
951                VariantKind::Tuple(t) => t.iter(),
952                VariantKind::Struct(s) => s.fields.iter(),
953            },
954            EnumItem(e) => e.variants.iter(),
955            TraitItem(t) => t.items.iter(),
956            ImplItem(i) => i.items.iter(),
957            ModuleItem(m) => m.items.iter(),
958            ExternCrateItem { .. }
959            | ImportItem(_)
960            | FunctionItem(_)
961            | TypeAliasItem(_)
962            | StaticItem(_)
963            | ConstantItem(_)
964            | TraitAliasItem(_)
965            | RequiredMethodItem(..)
966            | MethodItem(..)
967            | StructFieldItem(_)
968            | ForeignFunctionItem(_, _)
969            | ForeignStaticItem(_, _)
970            | ForeignTypeItem
971            | MacroItem(_)
972            | ProcMacroItem(_)
973            | PrimitiveItem(_)
974            | RequiredAssocConstItem(..)
975            | ProvidedAssocConstItem(..)
976            | ImplAssocConstItem(..)
977            | RequiredAssocTypeItem(..)
978            | AssocTypeItem(..)
979            | StrippedItem(_)
980            | KeywordItem
981            | AttributeItem
982            | PlaceholderImplItem => [].iter(),
983        }
984    }
985}
986
987#[derive(Clone, Debug)]
988pub(crate) struct Module {
989    pub(crate) items: Vec<Item>,
990    pub(crate) span: Span,
991}
992
993/// A link that has not yet been rendered.
994///
995/// This link will be turned into a rendered link by [`Item::links`].
996#[derive(Clone, Debug, PartialEq, Eq, Hash)]
997pub(crate) struct ItemLink {
998    /// The original link written in the markdown
999    pub(crate) link: Box<str>,
1000    /// The link text displayed in the HTML.
1001    ///
1002    /// This may not be the same as `link` if there was a disambiguator
1003    /// in an intra-doc link (e.g. \[`fn@f`\])
1004    pub(crate) link_text: Box<str>,
1005    /// The `DefId` of the Item whose **HTML Page** contains the item being
1006    /// linked to. This will be different to `item_id` on item's that don't
1007    /// have their own page, such as struct fields and enum variants.
1008    pub(crate) page_id: DefId,
1009    /// The url fragment to append to the link
1010    pub(crate) fragment: Option<UrlFragment>,
1011}
1012
1013pub struct RenderedLink {
1014    /// The text the link was original written as.
1015    ///
1016    /// This could potentially include disambiguators and backticks.
1017    pub(crate) original_text: Box<str>,
1018    /// The text to display in the HTML
1019    pub(crate) new_text: Box<str>,
1020    /// The URL to put in the `href`
1021    pub(crate) href: String,
1022    /// The tooltip.
1023    pub(crate) tooltip: String,
1024}
1025
1026/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1027/// as well as doc comments.
1028#[derive(Clone, Debug, Default)]
1029pub(crate) struct Attributes {
1030    pub(crate) doc_strings: Vec<DocFragment>,
1031    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1032}
1033
1034impl Attributes {
1035    pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool {
1036        find_attr!(&self.other_attrs, Doc(d) if callback(d))
1037    }
1038
1039    pub(crate) fn is_doc_hidden(&self) -> bool {
1040        find_attr!(&self.other_attrs, Doc(d) if d.hidden.is_some())
1041    }
1042
1043    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1044        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1045    }
1046
1047    pub(crate) fn from_hir_with_additional(
1048        attrs: &[hir::Attribute],
1049        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1050    ) -> Attributes {
1051        // Additional documentation should be shown before the original documentation.
1052        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1053        let attrs2 = attrs.iter().map(|attr| (attr, None));
1054        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1055    }
1056
1057    pub(crate) fn from_hir_iter<'a>(
1058        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1059        doc_only: bool,
1060    ) -> Attributes {
1061        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1062        Attributes { doc_strings, other_attrs }
1063    }
1064
1065    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1066    pub(crate) fn doc_value(&self) -> String {
1067        self.opt_doc_value().unwrap_or_default()
1068    }
1069
1070    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1071    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1072    /// documentation but it is empty (e.g. `#[doc = ""]`).
1073    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1074        (!self.doc_strings.is_empty()).then(|| {
1075            let mut res = String::new();
1076            for frag in &self.doc_strings {
1077                add_doc_fragment(&mut res, frag);
1078            }
1079            res.pop();
1080            res
1081        })
1082    }
1083
1084    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1085        let mut aliases = FxIndexSet::default();
1086
1087        for attr in &self.other_attrs {
1088            if let Attribute::Parsed(AttributeKind::Doc(d)) = attr {
1089                for (alias, _) in &d.aliases {
1090                    aliases.insert(*alias);
1091                }
1092            }
1093        }
1094        aliases.into_iter().collect::<Vec<_>>().into()
1095    }
1096}
1097
1098#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1099pub(crate) enum GenericBound {
1100    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1101    Outlives(Lifetime),
1102    /// `use<'a, T>` precise-capturing bound syntax
1103    Use(Vec<PreciseCapturingArg>),
1104}
1105
1106impl GenericBound {
1107    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1108        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1109    }
1110
1111    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1112        Self::sized_with(
1113            cx,
1114            hir::TraitBoundModifiers {
1115                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1116                constness: hir::BoundConstness::Never,
1117            },
1118        )
1119    }
1120
1121    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1122        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1123        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1124        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1125        inline::record_extern_fqn(cx, did, ItemType::Trait);
1126        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1127    }
1128
1129    pub(crate) fn is_trait_bound(&self) -> bool {
1130        matches!(self, Self::TraitBound(..))
1131    }
1132
1133    pub(crate) fn is_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1134        self.is_bounded_by_lang_item(tcx, LangItem::Sized)
1135    }
1136
1137    pub(crate) fn is_meta_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1138        self.is_bounded_by_lang_item(tcx, LangItem::MetaSized)
1139    }
1140
1141    fn is_bounded_by_lang_item(&self, tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
1142        if let GenericBound::TraitBound(
1143            PolyTrait { ref trait_, .. },
1144            rustc_hir::TraitBoundModifiers::NONE,
1145        ) = *self
1146            && tcx.is_lang_item(trait_.def_id(), lang_item)
1147        {
1148            return true;
1149        }
1150        false
1151    }
1152
1153    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1154        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1155            Some(trait_.clone())
1156        } else {
1157            None
1158        }
1159    }
1160}
1161
1162#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1163pub(crate) struct Lifetime(pub Symbol);
1164
1165impl Lifetime {
1166    pub(crate) fn statik() -> Lifetime {
1167        Lifetime(kw::StaticLifetime)
1168    }
1169
1170    pub(crate) fn elided() -> Lifetime {
1171        Lifetime(kw::UnderscoreLifetime)
1172    }
1173}
1174
1175#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1176pub(crate) enum PreciseCapturingArg {
1177    Lifetime(Lifetime),
1178    Param(Symbol),
1179}
1180
1181impl PreciseCapturingArg {
1182    pub(crate) fn name(self) -> Symbol {
1183        match self {
1184            PreciseCapturingArg::Lifetime(lt) => lt.0,
1185            PreciseCapturingArg::Param(param) => param,
1186        }
1187    }
1188}
1189
1190#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1191pub(crate) enum WherePredicate {
1192    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1193    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1194    EqPredicate { lhs: QPathData, rhs: Term },
1195}
1196
1197impl WherePredicate {
1198    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1199        match self {
1200            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1201            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1202            _ => None,
1203        }
1204    }
1205}
1206
1207#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1208pub(crate) enum GenericParamDefKind {
1209    Lifetime { outlives: ThinVec<Lifetime> },
1210    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1211    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1212    Const { ty: Box<Type>, default: Option<Box<String>> },
1213}
1214
1215impl GenericParamDefKind {
1216    pub(crate) fn is_type(&self) -> bool {
1217        matches!(self, GenericParamDefKind::Type { .. })
1218    }
1219}
1220
1221#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1222pub(crate) struct GenericParamDef {
1223    pub(crate) name: Symbol,
1224    pub(crate) def_id: DefId,
1225    pub(crate) kind: GenericParamDefKind,
1226}
1227
1228impl GenericParamDef {
1229    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1230        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1231    }
1232
1233    pub(crate) fn is_synthetic_param(&self) -> bool {
1234        match self.kind {
1235            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1236            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1237        }
1238    }
1239
1240    pub(crate) fn is_type(&self) -> bool {
1241        self.kind.is_type()
1242    }
1243
1244    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1245        match self.kind {
1246            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1247            _ => None,
1248        }
1249    }
1250}
1251
1252// maybe use a Generic enum and use Vec<Generic>?
1253#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1254pub(crate) struct Generics {
1255    pub(crate) params: ThinVec<GenericParamDef>,
1256    pub(crate) where_predicates: ThinVec<WherePredicate>,
1257}
1258
1259impl Generics {
1260    pub(crate) fn is_empty(&self) -> bool {
1261        self.params.is_empty() && self.where_predicates.is_empty()
1262    }
1263}
1264
1265#[derive(Clone, Debug)]
1266pub(crate) struct Function {
1267    pub(crate) decl: FnDecl,
1268    pub(crate) generics: Generics,
1269}
1270
1271#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1272pub(crate) struct FnDecl {
1273    pub(crate) inputs: Vec<Parameter>,
1274    pub(crate) output: Type,
1275    pub(crate) c_variadic: bool,
1276}
1277
1278impl FnDecl {
1279    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1280        self.inputs.first().and_then(|v| v.to_receiver())
1281    }
1282}
1283
1284/// A function parameter.
1285#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1286pub(crate) struct Parameter {
1287    pub(crate) name: Option<Symbol>,
1288    pub(crate) type_: Type,
1289    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1290    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1291    pub(crate) is_const: bool,
1292}
1293
1294impl Parameter {
1295    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1296        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1297    }
1298}
1299
1300#[derive(Clone, Debug)]
1301pub(crate) struct Trait {
1302    pub(crate) def_id: DefId,
1303    pub(crate) items: Vec<Item>,
1304    pub(crate) generics: Generics,
1305    pub(crate) bounds: Vec<GenericBound>,
1306}
1307
1308impl Trait {
1309    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1310        tcx.trait_is_auto(self.def_id)
1311    }
1312    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1313        tcx.is_doc_notable_trait(self.def_id)
1314    }
1315    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1316        tcx.trait_def(self.def_id).safety
1317    }
1318    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1319        tcx.is_dyn_compatible(self.def_id)
1320    }
1321    pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
1322        tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
1323    }
1324}
1325
1326#[derive(Clone, Debug)]
1327pub(crate) struct TraitAlias {
1328    pub(crate) generics: Generics,
1329    pub(crate) bounds: Vec<GenericBound>,
1330}
1331
1332/// A trait reference, which may have higher ranked lifetimes.
1333#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1334pub(crate) struct PolyTrait {
1335    pub(crate) trait_: Path,
1336    pub(crate) generic_params: Vec<GenericParamDef>,
1337}
1338
1339/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1340#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1341pub(crate) enum Type {
1342    /// A named type, which could be a trait.
1343    ///
1344    /// This is mostly Rustdoc's version of [`hir::Path`].
1345    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1346    Path {
1347        path: Path,
1348    },
1349    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1350    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1351    /// A type parameter.
1352    Generic(Symbol),
1353    /// The `Self` type.
1354    SelfTy,
1355    /// A primitive (aka, builtin) type.
1356    Primitive(PrimitiveType),
1357    /// A function pointer: `extern "ABI" fn(...) -> ...`
1358    BareFunction(Box<BareFunctionDecl>),
1359    /// A tuple type: `(i32, &str)`.
1360    Tuple(Vec<Type>),
1361    /// A slice type (does *not* include the `&`): `[i32]`
1362    Slice(Box<Type>),
1363    /// An array type.
1364    ///
1365    /// The `String` field is a stringified version of the array's length parameter.
1366    Array(Box<Type>, Box<str>),
1367    Pat(Box<Type>, Box<str>),
1368    FieldOf(Box<Type>, Box<str>),
1369    /// A raw pointer type: `*const i32`, `*mut i32`
1370    RawPointer(Mutability, Box<Type>),
1371    /// A reference type: `&i32`, `&'a mut Foo`
1372    BorrowedRef {
1373        lifetime: Option<Lifetime>,
1374        mutability: Mutability,
1375        type_: Box<Type>,
1376    },
1377
1378    /// A qualified path to an associated item: `<Type as Trait>::Name`
1379    QPath(Box<QPathData>),
1380
1381    /// A type that is inferred: `_`
1382    Infer,
1383
1384    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1385    ImplTrait(Vec<GenericBound>),
1386
1387    UnsafeBinder(Box<UnsafeBinderTy>),
1388}
1389
1390impl Type {
1391    /// When comparing types for equality, it can help to ignore `&` wrapping.
1392    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1393        let mut result = self;
1394        while let Type::BorrowedRef { type_, .. } = result {
1395            result = type_;
1396        }
1397        result
1398    }
1399
1400    pub(crate) fn is_borrowed_ref(&self) -> bool {
1401        matches!(self, Type::BorrowedRef { .. })
1402    }
1403
1404    fn is_type_alias(&self) -> bool {
1405        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1406    }
1407
1408    /// Check if this type is a subtype of another type for documentation purposes.
1409    ///
1410    /// This is different from `Eq`, because it knows that things like
1411    /// `Infer` and generics have special subtyping rules.
1412    ///
1413    /// This relation is not commutative when generics are involved:
1414    ///
1415    /// ```ignore(private)
1416    /// # // see types/tests.rs:is_same_generic for the real test
1417    /// use rustdoc::format::cache::Cache;
1418    /// use rustdoc::clean::types::{Type, PrimitiveType};
1419    /// let cache = Cache::new(false);
1420    /// let generic = Type::Generic(Symbol::intern("T"));
1421    /// let unit = Type::Primitive(PrimitiveType::Unit);
1422    /// assert!(!generic.is_doc_subtype_of(&unit, &cache));
1423    /// assert!(unit.is_doc_subtype_of(&generic, &cache));
1424    /// ```
1425    ///
1426    /// An owned type is also the same as its borrowed variants (this is commutative),
1427    /// but `&T` is not the same as `&mut T`.
1428    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1429        // Strip the references so that it can compare the actual types, unless both are references.
1430        // If both are references, leave them alone and compare the mutabilities later.
1431        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1432            (self.without_borrowed_ref(), other.without_borrowed_ref())
1433        } else {
1434            (self, other)
1435        };
1436
1437        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1438        // so we just assume they are equal.
1439        // This is only remotely acceptable because we were previously
1440        // assuming all types were equal when used
1441        // as a generic parameter of a type in `Deref::Target`.
1442        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1443            return true;
1444        }
1445
1446        match (self_cleared, other_cleared) {
1447            // Recursive cases.
1448            (Type::Tuple(a), Type::Tuple(b)) => {
1449                a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
1450            }
1451            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1452            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1453            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1454                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1455            }
1456            (
1457                Type::BorrowedRef { mutability, type_, .. },
1458                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1459            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1460            // Placeholders are equal to all other types.
1461            (Type::Infer, _) | (_, Type::Infer) => true,
1462            // Generics match everything on the right, but not on the left.
1463            // If both sides are generic, this returns true.
1464            (_, Type::Generic(_)) => true,
1465            (Type::Generic(_), _) => false,
1466            // `Self` only matches itself.
1467            (Type::SelfTy, Type::SelfTy) => true,
1468            // Paths account for both the path itself and its generics.
1469            (Type::Path { path: a }, Type::Path { path: b }) => {
1470                a.def_id() == b.def_id()
1471                    && a.generics()
1472                        .zip(b.generics())
1473                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1474                        .unwrap_or(true)
1475            }
1476            // Other cases, such as primitives, just use recursion.
1477            (a, b) => a
1478                .def_id(cache)
1479                .and_then(|a| Some((a, b.def_id(cache)?)))
1480                .map(|(a, b)| a == b)
1481                .unwrap_or(false),
1482        }
1483    }
1484
1485    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1486        match *self {
1487            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1488            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1489            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1490            Tuple(ref tys) => {
1491                if tys.is_empty() {
1492                    Some(PrimitiveType::Unit)
1493                } else {
1494                    Some(PrimitiveType::Tuple)
1495                }
1496            }
1497            RawPointer(..) => Some(PrimitiveType::RawPointer),
1498            BareFunction(..) => Some(PrimitiveType::Fn),
1499            _ => None,
1500        }
1501    }
1502
1503    /// Returns the sugared return type for an async function.
1504    ///
1505    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1506    /// will return `i32`.
1507    ///
1508    /// # Panics
1509    ///
1510    /// This function will panic if the return type does not match the expected sugaring for async
1511    /// functions.
1512    pub(crate) fn sugared_async_return_type(self) -> Type {
1513        if let Type::ImplTrait(mut v) = self
1514            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1515            && let Some(segment) = trait_.segments.pop()
1516            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1517            && let Some(constraint) = constraints.pop()
1518            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1519            && let Term::Type(ty) = term
1520        {
1521            ty
1522        } else {
1523            panic!("unexpected async fn return type")
1524        }
1525    }
1526
1527    /// Checks if this is a `T::Name` path for an associated type.
1528    pub(crate) fn is_assoc_ty(&self) -> bool {
1529        match self {
1530            Type::Path { path, .. } => path.is_assoc_ty(),
1531            _ => false,
1532        }
1533    }
1534
1535    pub(crate) fn is_self_type(&self) -> bool {
1536        matches!(*self, Type::SelfTy)
1537    }
1538
1539    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1540        match self {
1541            Type::Path { path, .. } => path.generic_args(),
1542            _ => None,
1543        }
1544    }
1545
1546    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1547        match self {
1548            Type::Path { path, .. } => path.generics(),
1549            _ => None,
1550        }
1551    }
1552
1553    pub(crate) fn is_full_generic(&self) -> bool {
1554        matches!(self, Type::Generic(_))
1555    }
1556
1557    pub(crate) fn is_unit(&self) -> bool {
1558        matches!(self, Type::Tuple(v) if v.is_empty())
1559    }
1560
1561    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1562    ///
1563    /// [clean]: crate::clean
1564    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1565        let t: PrimitiveType = match self {
1566            Type::Path { path } => return Some(path.def_id()),
1567            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1568            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1569            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1570            BorrowedRef { type_, .. } => return type_.def_id(cache),
1571            Tuple(tys) => {
1572                if tys.is_empty() {
1573                    PrimitiveType::Unit
1574                } else {
1575                    PrimitiveType::Tuple
1576                }
1577            }
1578            BareFunction(..) => PrimitiveType::Fn,
1579            Slice(..) => PrimitiveType::Slice,
1580            Array(..) => PrimitiveType::Array,
1581            Type::Pat(..) => PrimitiveType::Pat,
1582            Type::FieldOf(..) => PrimitiveType::FieldOf,
1583            RawPointer(..) => PrimitiveType::RawPointer,
1584            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1585            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1586        };
1587        Primitive(t).def_id(cache)
1588    }
1589}
1590
1591#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1592pub(crate) struct QPathData {
1593    pub assoc: PathSegment,
1594    pub self_type: Type,
1595    /// FIXME: compute this field on demand.
1596    pub should_fully_qualify: bool,
1597    pub trait_: Option<Path>,
1598}
1599
1600/// A primitive (aka, builtin) type.
1601///
1602/// This represents things like `i32`, `str`, etc.
1603///
1604/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1605/// paths, like [`Self::Unit`].
1606#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1607pub(crate) enum PrimitiveType {
1608    Isize,
1609    I8,
1610    I16,
1611    I32,
1612    I64,
1613    I128,
1614    Usize,
1615    U8,
1616    U16,
1617    U32,
1618    U64,
1619    U128,
1620    F16,
1621    F32,
1622    F64,
1623    F128,
1624    Char,
1625    Bool,
1626    Str,
1627    Slice,
1628    Array,
1629    Pat,
1630    FieldOf,
1631    Tuple,
1632    Unit,
1633    RawPointer,
1634    Reference,
1635    Fn,
1636    Never,
1637}
1638
1639type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1640impl PrimitiveType {
1641    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1642        use ast::{FloatTy, IntTy, UintTy};
1643        match prim {
1644            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1645            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1646            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1647            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1648            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1649            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1650            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1651            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1652            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1653            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1654            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1655            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1656            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1657            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1658            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1659            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1660            hir::PrimTy::Str => PrimitiveType::Str,
1661            hir::PrimTy::Bool => PrimitiveType::Bool,
1662            hir::PrimTy::Char => PrimitiveType::Char,
1663        }
1664    }
1665
1666    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1667        match s {
1668            sym::isize => Some(PrimitiveType::Isize),
1669            sym::i8 => Some(PrimitiveType::I8),
1670            sym::i16 => Some(PrimitiveType::I16),
1671            sym::i32 => Some(PrimitiveType::I32),
1672            sym::i64 => Some(PrimitiveType::I64),
1673            sym::i128 => Some(PrimitiveType::I128),
1674            sym::usize => Some(PrimitiveType::Usize),
1675            sym::u8 => Some(PrimitiveType::U8),
1676            sym::u16 => Some(PrimitiveType::U16),
1677            sym::u32 => Some(PrimitiveType::U32),
1678            sym::u64 => Some(PrimitiveType::U64),
1679            sym::u128 => Some(PrimitiveType::U128),
1680            sym::bool => Some(PrimitiveType::Bool),
1681            sym::char => Some(PrimitiveType::Char),
1682            sym::str => Some(PrimitiveType::Str),
1683            sym::f16 => Some(PrimitiveType::F16),
1684            sym::f32 => Some(PrimitiveType::F32),
1685            sym::f64 => Some(PrimitiveType::F64),
1686            sym::f128 => Some(PrimitiveType::F128),
1687            sym::array => Some(PrimitiveType::Array),
1688            sym::slice => Some(PrimitiveType::Slice),
1689            sym::tuple => Some(PrimitiveType::Tuple),
1690            sym::unit => Some(PrimitiveType::Unit),
1691            sym::pointer => Some(PrimitiveType::RawPointer),
1692            sym::reference => Some(PrimitiveType::Reference),
1693            kw::Fn => Some(PrimitiveType::Fn),
1694            sym::never => Some(PrimitiveType::Never),
1695            _ => None,
1696        }
1697    }
1698
1699    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1700        use PrimitiveType::*;
1701        use ty::{FloatTy, IntTy, UintTy};
1702        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1703
1704        let single = |x| iter::once(x).collect();
1705        CELL.get_or_init(move || {
1706            map! {
1707                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1708                I8 => single(SimplifiedType::Int(IntTy::I8)),
1709                I16 => single(SimplifiedType::Int(IntTy::I16)),
1710                I32 => single(SimplifiedType::Int(IntTy::I32)),
1711                I64 => single(SimplifiedType::Int(IntTy::I64)),
1712                I128 => single(SimplifiedType::Int(IntTy::I128)),
1713                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1714                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1715                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1716                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1717                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1718                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1719                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1720                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1721                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1722                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1723                Str => single(SimplifiedType::Str),
1724                Bool => single(SimplifiedType::Bool),
1725                Char => single(SimplifiedType::Char),
1726                Array => single(SimplifiedType::Array),
1727                Slice => single(SimplifiedType::Slice),
1728                // FIXME: If we ever add an inherent impl for tuples
1729                // with different lengths, they won't show in rustdoc.
1730                //
1731                // Either manually update this arrayvec at this point
1732                // or start with a more complex refactoring.
1733                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1734                Unit => single(SimplifiedType::Tuple(0)),
1735                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1736                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1737                // FIXME: This will be wrong if we ever add inherent impls
1738                // for function pointers.
1739                Fn => single(SimplifiedType::Function(1)),
1740                Never => single(SimplifiedType::Never),
1741            }
1742        })
1743    }
1744
1745    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1746        Self::simplified_types()
1747            .get(self)
1748            .into_iter()
1749            .flatten()
1750            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1751            .copied()
1752    }
1753
1754    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1755        Self::simplified_types()
1756            .values()
1757            .flatten()
1758            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1759            .copied()
1760    }
1761
1762    pub(crate) fn as_sym(&self) -> Symbol {
1763        use PrimitiveType::*;
1764        match self {
1765            Isize => sym::isize,
1766            I8 => sym::i8,
1767            I16 => sym::i16,
1768            I32 => sym::i32,
1769            I64 => sym::i64,
1770            I128 => sym::i128,
1771            Usize => sym::usize,
1772            U8 => sym::u8,
1773            U16 => sym::u16,
1774            U32 => sym::u32,
1775            U64 => sym::u64,
1776            U128 => sym::u128,
1777            F16 => sym::f16,
1778            F32 => sym::f32,
1779            F64 => sym::f64,
1780            F128 => sym::f128,
1781            Str => sym::str,
1782            Bool => sym::bool,
1783            Char => sym::char,
1784            Array => sym::array,
1785            Pat => sym::pat,
1786            FieldOf => sym::field_of,
1787            Slice => sym::slice,
1788            Tuple => sym::tuple,
1789            Unit => sym::unit,
1790            RawPointer => sym::pointer,
1791            Reference => sym::reference,
1792            Fn => kw::Fn,
1793            Never => sym::never,
1794        }
1795    }
1796
1797    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1798    /// Panics if there is no such module.
1799    ///
1800    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1801    /// primitives defined in `core`,
1802    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1803    /// will be picked.
1804    ///
1805    /// In particular, if a crate depends on both `std` and another crate that also defines
1806    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1807    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1808    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1809        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1810        PRIMITIVE_LOCATIONS.get_or_init(|| {
1811            let mut primitive_locations = FxIndexMap::default();
1812            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1813            // This is a degenerate case that I don't plan to support.
1814            for &crate_num in tcx.crates(()) {
1815                let e = ExternalCrate { crate_num };
1816                let crate_name = e.name(tcx);
1817                debug!(?crate_num, ?crate_name);
1818                for (def_id, prim) in e.primitives(tcx) {
1819                    // HACK: try to link to std instead where possible
1820                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1821                        continue;
1822                    }
1823                    primitive_locations.insert(prim, def_id);
1824                }
1825            }
1826            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1827            for (def_id, prim) in local_primitives {
1828                primitive_locations.insert(prim, def_id);
1829            }
1830            primitive_locations
1831        })
1832    }
1833}
1834
1835impl From<ty::IntTy> for PrimitiveType {
1836    fn from(int_ty: ty::IntTy) -> PrimitiveType {
1837        match int_ty {
1838            ty::IntTy::Isize => PrimitiveType::Isize,
1839            ty::IntTy::I8 => PrimitiveType::I8,
1840            ty::IntTy::I16 => PrimitiveType::I16,
1841            ty::IntTy::I32 => PrimitiveType::I32,
1842            ty::IntTy::I64 => PrimitiveType::I64,
1843            ty::IntTy::I128 => PrimitiveType::I128,
1844        }
1845    }
1846}
1847
1848impl From<ty::UintTy> for PrimitiveType {
1849    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1850        match uint_ty {
1851            ty::UintTy::Usize => PrimitiveType::Usize,
1852            ty::UintTy::U8 => PrimitiveType::U8,
1853            ty::UintTy::U16 => PrimitiveType::U16,
1854            ty::UintTy::U32 => PrimitiveType::U32,
1855            ty::UintTy::U64 => PrimitiveType::U64,
1856            ty::UintTy::U128 => PrimitiveType::U128,
1857        }
1858    }
1859}
1860
1861impl From<ty::FloatTy> for PrimitiveType {
1862    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1863        match float_ty {
1864            ty::FloatTy::F16 => PrimitiveType::F16,
1865            ty::FloatTy::F32 => PrimitiveType::F32,
1866            ty::FloatTy::F64 => PrimitiveType::F64,
1867            ty::FloatTy::F128 => PrimitiveType::F128,
1868        }
1869    }
1870}
1871
1872impl From<hir::PrimTy> for PrimitiveType {
1873    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1874        match prim_ty {
1875            hir::PrimTy::Int(int_ty) => int_ty.into(),
1876            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1877            hir::PrimTy::Float(float_ty) => float_ty.into(),
1878            hir::PrimTy::Str => PrimitiveType::Str,
1879            hir::PrimTy::Bool => PrimitiveType::Bool,
1880            hir::PrimTy::Char => PrimitiveType::Char,
1881        }
1882    }
1883}
1884
1885#[derive(Clone, Debug)]
1886pub(crate) struct Struct {
1887    pub(crate) ctor_kind: Option<CtorKind>,
1888    pub(crate) generics: Generics,
1889    pub(crate) fields: ThinVec<Item>,
1890}
1891
1892impl Struct {
1893    pub(crate) fn has_stripped_entries(&self) -> bool {
1894        self.fields.iter().any(|f| f.is_stripped())
1895    }
1896}
1897
1898#[derive(Clone, Debug)]
1899pub(crate) struct Union {
1900    pub(crate) generics: Generics,
1901    pub(crate) fields: Vec<Item>,
1902}
1903
1904impl Union {
1905    pub(crate) fn has_stripped_entries(&self) -> bool {
1906        self.fields.iter().any(|f| f.is_stripped())
1907    }
1908}
1909
1910/// This is a more limited form of the standard Struct, different in that
1911/// it lacks the things most items have (name, id, parameterization). Found
1912/// only as a variant in an enum.
1913#[derive(Clone, Debug)]
1914pub(crate) struct VariantStruct {
1915    pub(crate) fields: ThinVec<Item>,
1916}
1917
1918impl VariantStruct {
1919    pub(crate) fn has_stripped_entries(&self) -> bool {
1920        self.fields.iter().any(|f| f.is_stripped())
1921    }
1922}
1923
1924#[derive(Clone, Debug)]
1925pub(crate) struct Enum {
1926    pub(crate) variants: IndexVec<VariantIdx, Item>,
1927    pub(crate) generics: Generics,
1928}
1929
1930impl Enum {
1931    pub(crate) fn has_stripped_entries(&self) -> bool {
1932        self.variants.iter().any(|f| f.is_stripped())
1933    }
1934
1935    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
1936        self.variants.iter().filter(|v| !v.is_stripped())
1937    }
1938}
1939
1940#[derive(Clone, Debug)]
1941pub(crate) struct Variant {
1942    pub kind: VariantKind,
1943    pub discriminant: Option<Discriminant>,
1944}
1945
1946#[derive(Clone, Debug)]
1947pub(crate) enum VariantKind {
1948    CLike,
1949    Tuple(ThinVec<Item>),
1950    Struct(VariantStruct),
1951}
1952
1953impl Variant {
1954    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
1955        match &self.kind {
1956            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
1957            VariantKind::CLike | VariantKind::Tuple(_) => None,
1958        }
1959    }
1960}
1961
1962#[derive(Clone, Debug)]
1963pub(crate) struct Discriminant {
1964    // In the case of cross crate re-exports, we don't have the necessary information
1965    // to reconstruct the expression of the discriminant, only the value.
1966    pub(super) expr: Option<BodyId>,
1967    pub(super) value: DefId,
1968}
1969
1970impl Discriminant {
1971    /// Will be `None` in the case of cross-crate reexports, and may be
1972    /// simplified
1973    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
1974        self.expr
1975            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
1976    }
1977    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
1978        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
1979    }
1980}
1981
1982/// Small wrapper around [`rustc_span::Span`] that adds helper methods
1983/// and enforces calling [`rustc_span::Span::source_callsite()`].
1984#[derive(Copy, Clone, Debug)]
1985pub(crate) struct Span(rustc_span::Span);
1986
1987impl Span {
1988    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1989    /// span will be updated to point to the macro invocation instead of the macro definition.
1990    ///
1991    /// (See rust-lang/rust#39726)
1992    pub(crate) fn new(sp: rustc_span::Span) -> Self {
1993        Self(sp.source_callsite())
1994    }
1995
1996    pub(crate) fn inner(&self) -> rustc_span::Span {
1997        self.0
1998    }
1999
2000    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2001        sess.source_map().span_to_filename(self.0)
2002    }
2003
2004    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2005        sess.source_map().lookup_char_pos(self.0.lo())
2006    }
2007
2008    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2009        sess.source_map().lookup_char_pos(self.0.hi())
2010    }
2011
2012    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2013        // FIXME: is there a time when the lo and hi crate would be different?
2014        self.lo(sess).file.cnum
2015    }
2016}
2017
2018#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2019pub(crate) struct Path {
2020    pub(crate) res: Res,
2021    pub(crate) segments: ThinVec<PathSegment>,
2022}
2023
2024impl Path {
2025    pub(crate) fn def_id(&self) -> DefId {
2026        self.res.def_id()
2027    }
2028
2029    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2030        self.segments.last().map(|s| s.name)
2031    }
2032
2033    pub(crate) fn last(&self) -> Symbol {
2034        self.last_opt().expect("segments were empty")
2035    }
2036
2037    pub(crate) fn whole_name(&self) -> String {
2038        self.segments
2039            .iter()
2040            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2041            .intersperse("::")
2042            .collect()
2043    }
2044
2045    /// Checks if this is a `T::Name` path for an associated type.
2046    pub(crate) fn is_assoc_ty(&self) -> bool {
2047        match self.res {
2048            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2049                if self.segments.len() != 1 =>
2050            {
2051                true
2052            }
2053            Res::Def(DefKind::AssocTy, _) => true,
2054            _ => false,
2055        }
2056    }
2057
2058    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2059        self.segments.last().map(|seg| &seg.args)
2060    }
2061
2062    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2063        self.segments.last().and_then(|seg| {
2064            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2065                Some(args.iter().filter_map(|arg| match arg {
2066                    GenericArg::Type(ty) => Some(ty),
2067                    _ => None,
2068                }))
2069            } else {
2070                None
2071            }
2072        })
2073    }
2074}
2075
2076#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2077pub(crate) enum GenericArg {
2078    Lifetime(Lifetime),
2079    Type(Type),
2080    Const(Box<ConstantKind>),
2081    Infer,
2082}
2083
2084impl GenericArg {
2085    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2086        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2087    }
2088
2089    pub(crate) fn as_ty(&self) -> Option<&Type> {
2090        if let Self::Type(ty) = self { Some(ty) } else { None }
2091    }
2092}
2093
2094#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2095pub(crate) enum GenericArgs {
2096    /// `<args, constraints = ..>`
2097    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2098    /// `(inputs) -> output`
2099    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2100    /// `(..)`
2101    ReturnTypeNotation,
2102}
2103
2104impl GenericArgs {
2105    pub(crate) fn is_empty(&self) -> bool {
2106        match self {
2107            GenericArgs::AngleBracketed { args, constraints } => {
2108                args.is_empty() && constraints.is_empty()
2109            }
2110            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2111            GenericArgs::ReturnTypeNotation => false,
2112        }
2113    }
2114    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2115        match self {
2116            GenericArgs::AngleBracketed { constraints, .. } => {
2117                Box::new(constraints.iter().cloned())
2118            }
2119            GenericArgs::Parenthesized { output, .. } => Box::new(
2120                output
2121                    .as_ref()
2122                    .map(|ty| AssocItemConstraint {
2123                        assoc: PathSegment {
2124                            name: sym::Output,
2125                            args: GenericArgs::AngleBracketed {
2126                                args: ThinVec::new(),
2127                                constraints: ThinVec::new(),
2128                            },
2129                        },
2130                        kind: AssocItemConstraintKind::Equality {
2131                            term: Term::Type((**ty).clone()),
2132                        },
2133                    })
2134                    .into_iter(),
2135            ),
2136            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2137        }
2138    }
2139}
2140
2141impl<'a> IntoIterator for &'a GenericArgs {
2142    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2143    type Item = GenericArg;
2144    fn into_iter(self) -> Self::IntoIter {
2145        match self {
2146            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2147            GenericArgs::Parenthesized { inputs, .. } => {
2148                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2149                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2150            }
2151            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2152        }
2153    }
2154}
2155
2156#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2157pub(crate) struct PathSegment {
2158    pub(crate) name: Symbol,
2159    pub(crate) args: GenericArgs,
2160}
2161
2162#[derive(Clone, Debug)]
2163pub(crate) enum TypeAliasInnerType {
2164    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2165    Union { fields: Vec<Item> },
2166    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2167}
2168
2169impl TypeAliasInnerType {
2170    fn has_stripped_entries(&self) -> Option<bool> {
2171        Some(match self {
2172            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2173            Self::Union { fields } | Self::Struct { fields, .. } => {
2174                fields.iter().any(|f| f.is_stripped())
2175            }
2176        })
2177    }
2178}
2179
2180#[derive(Clone, Debug)]
2181pub(crate) struct TypeAlias {
2182    pub(crate) type_: Type,
2183    pub(crate) generics: Generics,
2184    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2185    /// to be shown directly on the typedef page.
2186    pub(crate) inner_type: Option<TypeAliasInnerType>,
2187    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2188    /// alias instead of the final type. This will always have the final type, regardless of whether
2189    /// `type_` came from HIR or from metadata.
2190    ///
2191    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2192    /// final type).
2193    pub(crate) item_type: Option<Type>,
2194}
2195
2196#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2197pub(crate) struct BareFunctionDecl {
2198    pub(crate) safety: hir::Safety,
2199    pub(crate) generic_params: Vec<GenericParamDef>,
2200    pub(crate) decl: FnDecl,
2201    pub(crate) abi: ExternAbi,
2202}
2203
2204#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2205pub(crate) struct UnsafeBinderTy {
2206    pub(crate) generic_params: Vec<GenericParamDef>,
2207    pub(crate) ty: Type,
2208}
2209
2210#[derive(Clone, Debug)]
2211pub(crate) struct Static {
2212    pub(crate) type_: Box<Type>,
2213    pub(crate) mutability: Mutability,
2214    pub(crate) expr: Option<BodyId>,
2215}
2216
2217#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2218pub(crate) struct Constant {
2219    pub(crate) generics: Generics,
2220    pub(crate) kind: ConstantKind,
2221    pub(crate) type_: Type,
2222}
2223
2224#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2225pub(crate) enum Term {
2226    Type(Type),
2227    Constant(ConstantKind),
2228}
2229
2230impl Term {
2231    pub(crate) fn ty(&self) -> Option<&Type> {
2232        if let Term::Type(ty) = self { Some(ty) } else { None }
2233    }
2234}
2235
2236impl From<Type> for Term {
2237    fn from(ty: Type) -> Self {
2238        Term::Type(ty)
2239    }
2240}
2241
2242#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2243pub(crate) enum ConstantKind {
2244    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2245    /// `BodyId`, we need to handle it on its own.
2246    ///
2247    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2248    /// by a DefId. So this field must be different from `Extern`.
2249    TyConst { expr: Box<str> },
2250    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2251    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2252    Path { path: Box<str> },
2253    /// A constant (expression) that's not an item or associated item. These are usually found
2254    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2255    /// used to define explicit discriminant values for enum variants.
2256    Anonymous { body: BodyId },
2257    /// A constant from a different crate.
2258    Extern { def_id: DefId },
2259    /// `const FOO: u32 = ...;`
2260    Local { def_id: DefId, body: BodyId },
2261    /// An inferred constant as in `[10u8; _]`.
2262    Infer,
2263}
2264
2265impl ConstantKind {
2266    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2267        match *self {
2268            ConstantKind::TyConst { ref expr } => expr.to_string(),
2269            ConstantKind::Path { ref path } => path.to_string(),
2270            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2271            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2272                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2273            }
2274            ConstantKind::Infer => "_".to_string(),
2275        }
2276    }
2277
2278    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2279        match *self {
2280            ConstantKind::TyConst { .. }
2281            | ConstantKind::Path { .. }
2282            | ConstantKind::Anonymous { .. }
2283            | ConstantKind::Infer => None,
2284            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2285                print_evaluated_const(tcx, def_id, true, true)
2286            }
2287        }
2288    }
2289
2290    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2291        match *self {
2292            ConstantKind::TyConst { .. }
2293            | ConstantKind::Extern { .. }
2294            | ConstantKind::Path { .. }
2295            | ConstantKind::Infer => false,
2296            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2297                is_literal_expr(tcx, body.hir_id)
2298            }
2299        }
2300    }
2301}
2302
2303#[derive(Clone, Debug)]
2304pub(crate) struct Impl {
2305    pub(crate) safety: hir::Safety,
2306    pub(crate) generics: Generics,
2307    pub(crate) trait_: Option<Path>,
2308    pub(crate) for_: Type,
2309    pub(crate) items: Vec<Item>,
2310    pub(crate) polarity: ty::ImplPolarity,
2311    pub(crate) kind: ImplKind,
2312    pub(crate) is_deprecated: bool,
2313}
2314
2315impl Impl {
2316    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2317        self.trait_
2318            .as_ref()
2319            .map(|t| t.def_id())
2320            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2321            .unwrap_or_default()
2322    }
2323
2324    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2325        matches!(self.polarity, ty::ImplPolarity::Negative)
2326    }
2327}
2328
2329#[derive(Clone, Debug)]
2330pub(crate) enum ImplKind {
2331    Normal,
2332    Auto,
2333    FakeVariadic,
2334    Blanket(Box<Type>),
2335}
2336
2337impl ImplKind {
2338    pub(crate) fn is_auto(&self) -> bool {
2339        matches!(self, ImplKind::Auto)
2340    }
2341
2342    pub(crate) fn is_blanket(&self) -> bool {
2343        matches!(self, ImplKind::Blanket(_))
2344    }
2345
2346    pub(crate) fn is_fake_variadic(&self) -> bool {
2347        matches!(self, ImplKind::FakeVariadic)
2348    }
2349
2350    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2351        match self {
2352            ImplKind::Blanket(ty) => Some(ty),
2353            _ => None,
2354        }
2355    }
2356}
2357
2358#[derive(Clone, Debug)]
2359pub(crate) struct Import {
2360    pub(crate) kind: ImportKind,
2361    /// The item being re-exported.
2362    pub(crate) source: ImportSource,
2363    pub(crate) should_be_displayed: bool,
2364}
2365
2366impl Import {
2367    pub(crate) fn new_simple(
2368        name: Symbol,
2369        source: ImportSource,
2370        should_be_displayed: bool,
2371    ) -> Self {
2372        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2373    }
2374
2375    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2376        Self { kind: ImportKind::Glob, source, should_be_displayed }
2377    }
2378
2379    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2380        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2381    }
2382}
2383
2384#[derive(Clone, Debug)]
2385pub(crate) enum ImportKind {
2386    // use source as str;
2387    Simple(Symbol),
2388    // use source::*;
2389    Glob,
2390}
2391
2392#[derive(Clone, Debug)]
2393pub(crate) struct ImportSource {
2394    pub(crate) path: Path,
2395    pub(crate) did: Option<DefId>,
2396}
2397
2398#[derive(Clone, Debug)]
2399pub(crate) struct Macro {
2400    pub(crate) source: String,
2401    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2402    pub(crate) macro_rules: bool,
2403}
2404
2405#[derive(Clone, Debug)]
2406pub(crate) struct ProcMacro {
2407    pub(crate) kind: MacroKind,
2408    pub(crate) helpers: Vec<Symbol>,
2409}
2410
2411/// A constraint on an associated item.
2412///
2413/// ### Examples
2414///
2415/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2416/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2417/// * the `A: Bound` in `Trait<A: Bound>`
2418/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2419/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2420/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2421#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2422pub(crate) struct AssocItemConstraint {
2423    pub(crate) assoc: PathSegment,
2424    pub(crate) kind: AssocItemConstraintKind,
2425}
2426
2427/// The kind of [associated item constraint][AssocItemConstraint].
2428#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2429pub(crate) enum AssocItemConstraintKind {
2430    Equality { term: Term },
2431    Bound { bounds: Vec<GenericBound> },
2432}
2433
2434// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2435#[cfg(target_pointer_width = "64")]
2436mod size_asserts {
2437    use rustc_data_structures::static_assert_size;
2438
2439    use super::*;
2440    // tidy-alphabetical-start
2441    static_assert_size!(Crate, 16); // frequently moved by-value
2442    static_assert_size!(DocFragment, 48);
2443    static_assert_size!(GenericArg, 32);
2444    static_assert_size!(GenericArgs, 24);
2445    static_assert_size!(GenericParamDef, 40);
2446    static_assert_size!(Generics, 16);
2447    static_assert_size!(Item, 8);
2448    static_assert_size!(ItemInner, 136);
2449    static_assert_size!(ItemKind, 48);
2450    static_assert_size!(PathSegment, 32);
2451    static_assert_size!(Type, 32);
2452    // tidy-alphabetical-end
2453}