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    pub(crate) fn merge_with(&mut self, other: Self) {
1098        let Self { doc_strings, other_attrs } = other;
1099        self.doc_strings.extend(doc_strings);
1100        self.other_attrs.extend(other_attrs);
1101    }
1102}
1103
1104#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1105pub(crate) enum GenericBound {
1106    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1107    Outlives(Lifetime),
1108    /// `use<'a, T>` precise-capturing bound syntax
1109    Use(Vec<PreciseCapturingArg>),
1110}
1111
1112impl GenericBound {
1113    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1114        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1115    }
1116
1117    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1118        Self::sized_with(
1119            cx,
1120            hir::TraitBoundModifiers {
1121                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1122                constness: hir::BoundConstness::Never,
1123            },
1124        )
1125    }
1126
1127    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1128        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1129        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1130        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1131        inline::record_extern_fqn(cx, did, ItemType::Trait);
1132        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1133    }
1134
1135    pub(crate) fn is_trait_bound(&self) -> bool {
1136        matches!(self, Self::TraitBound(..))
1137    }
1138
1139    pub(crate) fn is_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1140        self.is_bounded_by_lang_item(tcx, LangItem::Sized)
1141    }
1142
1143    pub(crate) fn is_meta_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1144        self.is_bounded_by_lang_item(tcx, LangItem::MetaSized)
1145    }
1146
1147    fn is_bounded_by_lang_item(&self, tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
1148        if let GenericBound::TraitBound(
1149            PolyTrait { ref trait_, .. },
1150            rustc_hir::TraitBoundModifiers::NONE,
1151        ) = *self
1152            && tcx.is_lang_item(trait_.def_id(), lang_item)
1153        {
1154            return true;
1155        }
1156        false
1157    }
1158
1159    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1160        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1161            Some(trait_.clone())
1162        } else {
1163            None
1164        }
1165    }
1166}
1167
1168#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1169pub(crate) struct Lifetime(pub Symbol);
1170
1171impl Lifetime {
1172    pub(crate) fn statik() -> Lifetime {
1173        Lifetime(kw::StaticLifetime)
1174    }
1175
1176    pub(crate) fn elided() -> Lifetime {
1177        Lifetime(kw::UnderscoreLifetime)
1178    }
1179}
1180
1181#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1182pub(crate) enum PreciseCapturingArg {
1183    Lifetime(Lifetime),
1184    Param(Symbol),
1185}
1186
1187impl PreciseCapturingArg {
1188    pub(crate) fn name(self) -> Symbol {
1189        match self {
1190            PreciseCapturingArg::Lifetime(lt) => lt.0,
1191            PreciseCapturingArg::Param(param) => param,
1192        }
1193    }
1194}
1195
1196#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1197pub(crate) enum WherePredicate {
1198    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1199    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1200    EqPredicate { lhs: QPathData, rhs: Term },
1201}
1202
1203impl WherePredicate {
1204    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1205        match self {
1206            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1207            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1208            _ => None,
1209        }
1210    }
1211}
1212
1213#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1214pub(crate) enum GenericParamDefKind {
1215    Lifetime { outlives: ThinVec<Lifetime> },
1216    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1217    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1218    Const { ty: Box<Type>, default: Option<Box<String>> },
1219}
1220
1221impl GenericParamDefKind {
1222    pub(crate) fn is_type(&self) -> bool {
1223        matches!(self, GenericParamDefKind::Type { .. })
1224    }
1225}
1226
1227#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1228pub(crate) struct GenericParamDef {
1229    pub(crate) name: Symbol,
1230    pub(crate) def_id: DefId,
1231    pub(crate) kind: GenericParamDefKind,
1232}
1233
1234impl GenericParamDef {
1235    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1236        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1237    }
1238
1239    pub(crate) fn is_synthetic_param(&self) -> bool {
1240        match self.kind {
1241            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1242            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1243        }
1244    }
1245
1246    pub(crate) fn is_type(&self) -> bool {
1247        self.kind.is_type()
1248    }
1249
1250    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1251        match self.kind {
1252            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1253            _ => None,
1254        }
1255    }
1256}
1257
1258// maybe use a Generic enum and use Vec<Generic>?
1259#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1260pub(crate) struct Generics {
1261    pub(crate) params: ThinVec<GenericParamDef>,
1262    pub(crate) where_predicates: ThinVec<WherePredicate>,
1263}
1264
1265impl Generics {
1266    pub(crate) fn is_empty(&self) -> bool {
1267        self.params.is_empty() && self.where_predicates.is_empty()
1268    }
1269}
1270
1271#[derive(Clone, Debug)]
1272pub(crate) struct Function {
1273    pub(crate) decl: FnDecl,
1274    pub(crate) generics: Generics,
1275}
1276
1277#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1278pub(crate) struct FnDecl {
1279    pub(crate) inputs: Vec<Parameter>,
1280    pub(crate) output: Type,
1281    pub(crate) c_variadic: bool,
1282}
1283
1284impl FnDecl {
1285    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1286        self.inputs.first().and_then(|v| v.to_receiver())
1287    }
1288}
1289
1290/// A function parameter.
1291#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1292pub(crate) struct Parameter {
1293    pub(crate) name: Option<Symbol>,
1294    pub(crate) type_: Type,
1295    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1296    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1297    pub(crate) is_const: bool,
1298}
1299
1300impl Parameter {
1301    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1302        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1303    }
1304}
1305
1306#[derive(Clone, Debug)]
1307pub(crate) struct Trait {
1308    pub(crate) def_id: DefId,
1309    pub(crate) items: Vec<Item>,
1310    pub(crate) generics: Generics,
1311    pub(crate) bounds: Vec<GenericBound>,
1312}
1313
1314impl Trait {
1315    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1316        tcx.trait_is_auto(self.def_id)
1317    }
1318    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1319        tcx.is_doc_notable_trait(self.def_id)
1320    }
1321    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1322        tcx.trait_def(self.def_id).safety
1323    }
1324    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1325        tcx.is_dyn_compatible(self.def_id)
1326    }
1327    pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
1328        tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
1329    }
1330}
1331
1332#[derive(Clone, Debug)]
1333pub(crate) struct TraitAlias {
1334    pub(crate) generics: Generics,
1335    pub(crate) bounds: Vec<GenericBound>,
1336}
1337
1338/// A trait reference, which may have higher ranked lifetimes.
1339#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1340pub(crate) struct PolyTrait {
1341    pub(crate) trait_: Path,
1342    pub(crate) generic_params: Vec<GenericParamDef>,
1343}
1344
1345/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1346#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1347pub(crate) enum Type {
1348    /// A named type, which could be a trait.
1349    ///
1350    /// This is mostly Rustdoc's version of [`hir::Path`].
1351    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1352    Path {
1353        path: Path,
1354    },
1355    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1356    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1357    /// A type parameter.
1358    Generic(Symbol),
1359    /// The `Self` type.
1360    SelfTy,
1361    /// A primitive (aka, builtin) type.
1362    Primitive(PrimitiveType),
1363    /// A function pointer: `extern "ABI" fn(...) -> ...`
1364    BareFunction(Box<BareFunctionDecl>),
1365    /// A tuple type: `(i32, &str)`.
1366    Tuple(Vec<Type>),
1367    /// A slice type (does *not* include the `&`): `[i32]`
1368    Slice(Box<Type>),
1369    /// An array type.
1370    ///
1371    /// The `String` field is a stringified version of the array's length parameter.
1372    Array(Box<Type>, Box<str>),
1373    Pat(Box<Type>, Box<str>),
1374    FieldOf(Box<Type>, Box<str>),
1375    /// A raw pointer type: `*const i32`, `*mut i32`
1376    RawPointer(Mutability, Box<Type>),
1377    /// A reference type: `&i32`, `&'a mut Foo`
1378    BorrowedRef {
1379        lifetime: Option<Lifetime>,
1380        mutability: Mutability,
1381        type_: Box<Type>,
1382    },
1383
1384    /// A qualified path to an associated item: `<Type as Trait>::Name`
1385    QPath(Box<QPathData>),
1386
1387    /// A type that is inferred: `_`
1388    Infer,
1389
1390    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1391    ImplTrait(Vec<GenericBound>),
1392
1393    UnsafeBinder(Box<UnsafeBinderTy>),
1394}
1395
1396impl Type {
1397    /// When comparing types for equality, it can help to ignore `&` wrapping.
1398    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1399        let mut result = self;
1400        while let Type::BorrowedRef { type_, .. } = result {
1401            result = type_;
1402        }
1403        result
1404    }
1405
1406    pub(crate) fn is_borrowed_ref(&self) -> bool {
1407        matches!(self, Type::BorrowedRef { .. })
1408    }
1409
1410    fn is_type_alias(&self) -> bool {
1411        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1412    }
1413
1414    /// Check if this type is a subtype of another type for documentation purposes.
1415    ///
1416    /// This is different from `Eq`, because it knows that things like
1417    /// `Infer` and generics have special subtyping rules.
1418    ///
1419    /// This relation is not commutative when generics are involved:
1420    ///
1421    /// ```ignore(private)
1422    /// # // see types/tests.rs:is_same_generic for the real test
1423    /// use rustdoc::format::cache::Cache;
1424    /// use rustdoc::clean::types::{Type, PrimitiveType};
1425    /// let cache = Cache::new(false);
1426    /// let generic = Type::Generic(Symbol::intern("T"));
1427    /// let unit = Type::Primitive(PrimitiveType::Unit);
1428    /// assert!(!generic.is_doc_subtype_of(&unit, &cache));
1429    /// assert!(unit.is_doc_subtype_of(&generic, &cache));
1430    /// ```
1431    ///
1432    /// An owned type is also the same as its borrowed variants (this is commutative),
1433    /// but `&T` is not the same as `&mut T`.
1434    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1435        // Strip the references so that it can compare the actual types, unless both are references.
1436        // If both are references, leave them alone and compare the mutabilities later.
1437        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1438            (self.without_borrowed_ref(), other.without_borrowed_ref())
1439        } else {
1440            (self, other)
1441        };
1442
1443        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1444        // so we just assume they are equal.
1445        // This is only remotely acceptable because we were previously
1446        // assuming all types were equal when used
1447        // as a generic parameter of a type in `Deref::Target`.
1448        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1449            return true;
1450        }
1451
1452        match (self_cleared, other_cleared) {
1453            // Recursive cases.
1454            (Type::Tuple(a), Type::Tuple(b)) => {
1455                a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
1456            }
1457            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1458            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1459            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1460                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1461            }
1462            (
1463                Type::BorrowedRef { mutability, type_, .. },
1464                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1465            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1466            // Placeholders are equal to all other types.
1467            (Type::Infer, _) | (_, Type::Infer) => true,
1468            // Generics match everything on the right, but not on the left.
1469            // If both sides are generic, this returns true.
1470            (_, Type::Generic(_)) => true,
1471            (Type::Generic(_), _) => false,
1472            // `Self` only matches itself.
1473            (Type::SelfTy, Type::SelfTy) => true,
1474            // Paths account for both the path itself and its generics.
1475            (Type::Path { path: a }, Type::Path { path: b }) => {
1476                a.def_id() == b.def_id()
1477                    && a.generics()
1478                        .zip(b.generics())
1479                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1480                        .unwrap_or(true)
1481            }
1482            // Other cases, such as primitives, just use recursion.
1483            (a, b) => a
1484                .def_id(cache)
1485                .and_then(|a| Some((a, b.def_id(cache)?)))
1486                .map(|(a, b)| a == b)
1487                .unwrap_or(false),
1488        }
1489    }
1490
1491    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1492        match *self {
1493            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1494            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1495            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1496            Tuple(ref tys) => {
1497                if tys.is_empty() {
1498                    Some(PrimitiveType::Unit)
1499                } else {
1500                    Some(PrimitiveType::Tuple)
1501                }
1502            }
1503            RawPointer(..) => Some(PrimitiveType::RawPointer),
1504            BareFunction(..) => Some(PrimitiveType::Fn),
1505            _ => None,
1506        }
1507    }
1508
1509    /// Returns the sugared return type for an async function.
1510    ///
1511    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1512    /// will return `i32`.
1513    ///
1514    /// # Panics
1515    ///
1516    /// This function will panic if the return type does not match the expected sugaring for async
1517    /// functions.
1518    pub(crate) fn sugared_async_return_type(self) -> Type {
1519        if let Type::ImplTrait(mut v) = self
1520            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1521            && let Some(segment) = trait_.segments.pop()
1522            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1523            && let Some(constraint) = constraints.pop()
1524            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1525            && let Term::Type(ty) = term
1526        {
1527            ty
1528        } else {
1529            panic!("unexpected async fn return type")
1530        }
1531    }
1532
1533    /// Checks if this is a `T::Name` path for an associated type.
1534    pub(crate) fn is_assoc_ty(&self) -> bool {
1535        match self {
1536            Type::Path { path, .. } => path.is_assoc_ty(),
1537            _ => false,
1538        }
1539    }
1540
1541    pub(crate) fn is_self_type(&self) -> bool {
1542        matches!(*self, Type::SelfTy)
1543    }
1544
1545    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1546        match self {
1547            Type::Path { path, .. } => path.generic_args(),
1548            _ => None,
1549        }
1550    }
1551
1552    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1553        match self {
1554            Type::Path { path, .. } => path.generics(),
1555            _ => None,
1556        }
1557    }
1558
1559    pub(crate) fn is_full_generic(&self) -> bool {
1560        matches!(self, Type::Generic(_))
1561    }
1562
1563    pub(crate) fn is_unit(&self) -> bool {
1564        matches!(self, Type::Tuple(v) if v.is_empty())
1565    }
1566
1567    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1568    ///
1569    /// [clean]: crate::clean
1570    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1571        let t: PrimitiveType = match self {
1572            Type::Path { path } => return Some(path.def_id()),
1573            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1574            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1575            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1576            BorrowedRef { type_, .. } => return type_.def_id(cache),
1577            Tuple(tys) => {
1578                if tys.is_empty() {
1579                    PrimitiveType::Unit
1580                } else {
1581                    PrimitiveType::Tuple
1582                }
1583            }
1584            BareFunction(..) => PrimitiveType::Fn,
1585            Slice(..) => PrimitiveType::Slice,
1586            Array(..) => PrimitiveType::Array,
1587            Type::Pat(..) => PrimitiveType::Pat,
1588            Type::FieldOf(..) => PrimitiveType::FieldOf,
1589            RawPointer(..) => PrimitiveType::RawPointer,
1590            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1591            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1592        };
1593        Primitive(t).def_id(cache)
1594    }
1595}
1596
1597#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1598pub(crate) struct QPathData {
1599    pub assoc: PathSegment,
1600    pub self_type: Type,
1601    /// FIXME: compute this field on demand.
1602    pub should_fully_qualify: bool,
1603    pub trait_: Option<Path>,
1604}
1605
1606/// A primitive (aka, builtin) type.
1607///
1608/// This represents things like `i32`, `str`, etc.
1609///
1610/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1611/// paths, like [`Self::Unit`].
1612#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1613pub(crate) enum PrimitiveType {
1614    Isize,
1615    I8,
1616    I16,
1617    I32,
1618    I64,
1619    I128,
1620    Usize,
1621    U8,
1622    U16,
1623    U32,
1624    U64,
1625    U128,
1626    F16,
1627    F32,
1628    F64,
1629    F128,
1630    Char,
1631    Bool,
1632    Str,
1633    Slice,
1634    Array,
1635    Pat,
1636    FieldOf,
1637    Tuple,
1638    Unit,
1639    RawPointer,
1640    Reference,
1641    Fn,
1642    Never,
1643}
1644
1645type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1646impl PrimitiveType {
1647    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1648        use ast::{FloatTy, IntTy, UintTy};
1649        match prim {
1650            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1651            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1652            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1653            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1654            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1655            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1656            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1657            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1658            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1659            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1660            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1661            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1662            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1663            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1664            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1665            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1666            hir::PrimTy::Str => PrimitiveType::Str,
1667            hir::PrimTy::Bool => PrimitiveType::Bool,
1668            hir::PrimTy::Char => PrimitiveType::Char,
1669        }
1670    }
1671
1672    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1673        match s {
1674            sym::isize => Some(PrimitiveType::Isize),
1675            sym::i8 => Some(PrimitiveType::I8),
1676            sym::i16 => Some(PrimitiveType::I16),
1677            sym::i32 => Some(PrimitiveType::I32),
1678            sym::i64 => Some(PrimitiveType::I64),
1679            sym::i128 => Some(PrimitiveType::I128),
1680            sym::usize => Some(PrimitiveType::Usize),
1681            sym::u8 => Some(PrimitiveType::U8),
1682            sym::u16 => Some(PrimitiveType::U16),
1683            sym::u32 => Some(PrimitiveType::U32),
1684            sym::u64 => Some(PrimitiveType::U64),
1685            sym::u128 => Some(PrimitiveType::U128),
1686            sym::bool => Some(PrimitiveType::Bool),
1687            sym::char => Some(PrimitiveType::Char),
1688            sym::str => Some(PrimitiveType::Str),
1689            sym::f16 => Some(PrimitiveType::F16),
1690            sym::f32 => Some(PrimitiveType::F32),
1691            sym::f64 => Some(PrimitiveType::F64),
1692            sym::f128 => Some(PrimitiveType::F128),
1693            sym::array => Some(PrimitiveType::Array),
1694            sym::slice => Some(PrimitiveType::Slice),
1695            sym::tuple => Some(PrimitiveType::Tuple),
1696            sym::unit => Some(PrimitiveType::Unit),
1697            sym::pointer => Some(PrimitiveType::RawPointer),
1698            sym::reference => Some(PrimitiveType::Reference),
1699            kw::Fn => Some(PrimitiveType::Fn),
1700            sym::never => Some(PrimitiveType::Never),
1701            _ => None,
1702        }
1703    }
1704
1705    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1706        use PrimitiveType::*;
1707        use ty::{FloatTy, IntTy, UintTy};
1708        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1709
1710        let single = |x| iter::once(x).collect();
1711        CELL.get_or_init(move || {
1712            map! {
1713                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1714                I8 => single(SimplifiedType::Int(IntTy::I8)),
1715                I16 => single(SimplifiedType::Int(IntTy::I16)),
1716                I32 => single(SimplifiedType::Int(IntTy::I32)),
1717                I64 => single(SimplifiedType::Int(IntTy::I64)),
1718                I128 => single(SimplifiedType::Int(IntTy::I128)),
1719                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1720                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1721                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1722                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1723                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1724                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1725                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1726                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1727                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1728                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1729                Str => single(SimplifiedType::Str),
1730                Bool => single(SimplifiedType::Bool),
1731                Char => single(SimplifiedType::Char),
1732                Array => single(SimplifiedType::Array),
1733                Slice => single(SimplifiedType::Slice),
1734                // FIXME: If we ever add an inherent impl for tuples
1735                // with different lengths, they won't show in rustdoc.
1736                //
1737                // Either manually update this arrayvec at this point
1738                // or start with a more complex refactoring.
1739                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1740                Unit => single(SimplifiedType::Tuple(0)),
1741                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1742                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1743                // FIXME: This will be wrong if we ever add inherent impls
1744                // for function pointers.
1745                Fn => single(SimplifiedType::Function(1)),
1746                Never => single(SimplifiedType::Never),
1747            }
1748        })
1749    }
1750
1751    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1752        Self::simplified_types()
1753            .get(self)
1754            .into_iter()
1755            .flatten()
1756            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1757            .copied()
1758    }
1759
1760    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1761        Self::simplified_types()
1762            .values()
1763            .flatten()
1764            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1765            .copied()
1766    }
1767
1768    pub(crate) fn as_sym(&self) -> Symbol {
1769        use PrimitiveType::*;
1770        match self {
1771            Isize => sym::isize,
1772            I8 => sym::i8,
1773            I16 => sym::i16,
1774            I32 => sym::i32,
1775            I64 => sym::i64,
1776            I128 => sym::i128,
1777            Usize => sym::usize,
1778            U8 => sym::u8,
1779            U16 => sym::u16,
1780            U32 => sym::u32,
1781            U64 => sym::u64,
1782            U128 => sym::u128,
1783            F16 => sym::f16,
1784            F32 => sym::f32,
1785            F64 => sym::f64,
1786            F128 => sym::f128,
1787            Str => sym::str,
1788            Bool => sym::bool,
1789            Char => sym::char,
1790            Array => sym::array,
1791            Pat => sym::pat,
1792            FieldOf => sym::field_of,
1793            Slice => sym::slice,
1794            Tuple => sym::tuple,
1795            Unit => sym::unit,
1796            RawPointer => sym::pointer,
1797            Reference => sym::reference,
1798            Fn => kw::Fn,
1799            Never => sym::never,
1800        }
1801    }
1802
1803    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1804    /// Panics if there is no such module.
1805    ///
1806    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1807    /// primitives defined in `core`,
1808    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1809    /// will be picked.
1810    ///
1811    /// In particular, if a crate depends on both `std` and another crate that also defines
1812    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1813    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1814    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1815        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1816        PRIMITIVE_LOCATIONS.get_or_init(|| {
1817            let mut primitive_locations = FxIndexMap::default();
1818            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1819            // This is a degenerate case that I don't plan to support.
1820            for &crate_num in tcx.crates(()) {
1821                let e = ExternalCrate { crate_num };
1822                let crate_name = e.name(tcx);
1823                debug!(?crate_num, ?crate_name);
1824                for (def_id, prim) in e.primitives(tcx) {
1825                    // HACK: try to link to std instead where possible
1826                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1827                        continue;
1828                    }
1829                    primitive_locations.insert(prim, def_id);
1830                }
1831            }
1832            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1833            for (def_id, prim) in local_primitives {
1834                primitive_locations.insert(prim, def_id);
1835            }
1836            primitive_locations
1837        })
1838    }
1839}
1840
1841impl From<ty::IntTy> for PrimitiveType {
1842    fn from(int_ty: ty::IntTy) -> PrimitiveType {
1843        match int_ty {
1844            ty::IntTy::Isize => PrimitiveType::Isize,
1845            ty::IntTy::I8 => PrimitiveType::I8,
1846            ty::IntTy::I16 => PrimitiveType::I16,
1847            ty::IntTy::I32 => PrimitiveType::I32,
1848            ty::IntTy::I64 => PrimitiveType::I64,
1849            ty::IntTy::I128 => PrimitiveType::I128,
1850        }
1851    }
1852}
1853
1854impl From<ty::UintTy> for PrimitiveType {
1855    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1856        match uint_ty {
1857            ty::UintTy::Usize => PrimitiveType::Usize,
1858            ty::UintTy::U8 => PrimitiveType::U8,
1859            ty::UintTy::U16 => PrimitiveType::U16,
1860            ty::UintTy::U32 => PrimitiveType::U32,
1861            ty::UintTy::U64 => PrimitiveType::U64,
1862            ty::UintTy::U128 => PrimitiveType::U128,
1863        }
1864    }
1865}
1866
1867impl From<ty::FloatTy> for PrimitiveType {
1868    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1869        match float_ty {
1870            ty::FloatTy::F16 => PrimitiveType::F16,
1871            ty::FloatTy::F32 => PrimitiveType::F32,
1872            ty::FloatTy::F64 => PrimitiveType::F64,
1873            ty::FloatTy::F128 => PrimitiveType::F128,
1874        }
1875    }
1876}
1877
1878impl From<hir::PrimTy> for PrimitiveType {
1879    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1880        match prim_ty {
1881            hir::PrimTy::Int(int_ty) => int_ty.into(),
1882            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1883            hir::PrimTy::Float(float_ty) => float_ty.into(),
1884            hir::PrimTy::Str => PrimitiveType::Str,
1885            hir::PrimTy::Bool => PrimitiveType::Bool,
1886            hir::PrimTy::Char => PrimitiveType::Char,
1887        }
1888    }
1889}
1890
1891#[derive(Clone, Debug)]
1892pub(crate) struct Struct {
1893    pub(crate) ctor_kind: Option<CtorKind>,
1894    pub(crate) generics: Generics,
1895    pub(crate) fields: ThinVec<Item>,
1896}
1897
1898impl Struct {
1899    pub(crate) fn has_stripped_entries(&self) -> bool {
1900        self.fields.iter().any(|f| f.is_stripped())
1901    }
1902}
1903
1904#[derive(Clone, Debug)]
1905pub(crate) struct Union {
1906    pub(crate) generics: Generics,
1907    pub(crate) fields: Vec<Item>,
1908}
1909
1910impl Union {
1911    pub(crate) fn has_stripped_entries(&self) -> bool {
1912        self.fields.iter().any(|f| f.is_stripped())
1913    }
1914}
1915
1916/// This is a more limited form of the standard Struct, different in that
1917/// it lacks the things most items have (name, id, parameterization). Found
1918/// only as a variant in an enum.
1919#[derive(Clone, Debug)]
1920pub(crate) struct VariantStruct {
1921    pub(crate) fields: ThinVec<Item>,
1922}
1923
1924impl VariantStruct {
1925    pub(crate) fn has_stripped_entries(&self) -> bool {
1926        self.fields.iter().any(|f| f.is_stripped())
1927    }
1928}
1929
1930#[derive(Clone, Debug)]
1931pub(crate) struct Enum {
1932    pub(crate) variants: IndexVec<VariantIdx, Item>,
1933    pub(crate) generics: Generics,
1934}
1935
1936impl Enum {
1937    pub(crate) fn has_stripped_entries(&self) -> bool {
1938        self.variants.iter().any(|f| f.is_stripped())
1939    }
1940
1941    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
1942        self.variants.iter().filter(|v| !v.is_stripped())
1943    }
1944}
1945
1946#[derive(Clone, Debug)]
1947pub(crate) struct Variant {
1948    pub kind: VariantKind,
1949    pub discriminant: Option<Discriminant>,
1950}
1951
1952#[derive(Clone, Debug)]
1953pub(crate) enum VariantKind {
1954    CLike,
1955    Tuple(ThinVec<Item>),
1956    Struct(VariantStruct),
1957}
1958
1959impl Variant {
1960    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
1961        match &self.kind {
1962            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
1963            VariantKind::CLike | VariantKind::Tuple(_) => None,
1964        }
1965    }
1966}
1967
1968#[derive(Clone, Debug)]
1969pub(crate) struct Discriminant {
1970    // In the case of cross crate re-exports, we don't have the necessary information
1971    // to reconstruct the expression of the discriminant, only the value.
1972    pub(super) expr: Option<BodyId>,
1973    pub(super) value: DefId,
1974}
1975
1976impl Discriminant {
1977    /// Will be `None` in the case of cross-crate reexports, and may be
1978    /// simplified
1979    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
1980        self.expr
1981            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
1982    }
1983    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
1984        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
1985    }
1986}
1987
1988/// Small wrapper around [`rustc_span::Span`] that adds helper methods
1989/// and enforces calling [`rustc_span::Span::source_callsite()`].
1990#[derive(Copy, Clone, Debug)]
1991pub(crate) struct Span(rustc_span::Span);
1992
1993impl Span {
1994    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1995    /// span will be updated to point to the macro invocation instead of the macro definition.
1996    ///
1997    /// (See rust-lang/rust#39726)
1998    pub(crate) fn new(sp: rustc_span::Span) -> Self {
1999        Self(sp.source_callsite())
2000    }
2001
2002    pub(crate) fn inner(&self) -> rustc_span::Span {
2003        self.0
2004    }
2005
2006    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2007        sess.source_map().span_to_filename(self.0)
2008    }
2009
2010    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2011        sess.source_map().lookup_char_pos(self.0.lo())
2012    }
2013
2014    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2015        sess.source_map().lookup_char_pos(self.0.hi())
2016    }
2017
2018    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2019        // FIXME: is there a time when the lo and hi crate would be different?
2020        self.lo(sess).file.cnum
2021    }
2022}
2023
2024#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2025pub(crate) struct Path {
2026    pub(crate) res: Res,
2027    pub(crate) segments: ThinVec<PathSegment>,
2028}
2029
2030impl Path {
2031    pub(crate) fn def_id(&self) -> DefId {
2032        self.res.def_id()
2033    }
2034
2035    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2036        self.segments.last().map(|s| s.name)
2037    }
2038
2039    pub(crate) fn last(&self) -> Symbol {
2040        self.last_opt().expect("segments were empty")
2041    }
2042
2043    pub(crate) fn whole_name(&self) -> String {
2044        self.segments
2045            .iter()
2046            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2047            .intersperse("::")
2048            .collect()
2049    }
2050
2051    /// Checks if this is a `T::Name` path for an associated type.
2052    pub(crate) fn is_assoc_ty(&self) -> bool {
2053        match self.res {
2054            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2055                if self.segments.len() != 1 =>
2056            {
2057                true
2058            }
2059            Res::Def(DefKind::AssocTy, _) => true,
2060            _ => false,
2061        }
2062    }
2063
2064    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2065        self.segments.last().map(|seg| &seg.args)
2066    }
2067
2068    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2069        self.segments.last().and_then(|seg| {
2070            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2071                Some(args.iter().filter_map(|arg| match arg {
2072                    GenericArg::Type(ty) => Some(ty),
2073                    _ => None,
2074                }))
2075            } else {
2076                None
2077            }
2078        })
2079    }
2080}
2081
2082#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2083pub(crate) enum GenericArg {
2084    Lifetime(Lifetime),
2085    Type(Type),
2086    Const(Box<ConstantKind>),
2087    Infer,
2088}
2089
2090impl GenericArg {
2091    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2092        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2093    }
2094
2095    pub(crate) fn as_ty(&self) -> Option<&Type> {
2096        if let Self::Type(ty) = self { Some(ty) } else { None }
2097    }
2098}
2099
2100#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2101pub(crate) enum GenericArgs {
2102    /// `<args, constraints = ..>`
2103    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2104    /// `(inputs) -> output`
2105    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2106    /// `(..)`
2107    ReturnTypeNotation,
2108}
2109
2110impl GenericArgs {
2111    pub(crate) fn is_empty(&self) -> bool {
2112        match self {
2113            GenericArgs::AngleBracketed { args, constraints } => {
2114                args.is_empty() && constraints.is_empty()
2115            }
2116            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2117            GenericArgs::ReturnTypeNotation => false,
2118        }
2119    }
2120    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2121        match self {
2122            GenericArgs::AngleBracketed { constraints, .. } => {
2123                Box::new(constraints.iter().cloned())
2124            }
2125            GenericArgs::Parenthesized { output, .. } => Box::new(
2126                output
2127                    .as_ref()
2128                    .map(|ty| AssocItemConstraint {
2129                        assoc: PathSegment {
2130                            name: sym::Output,
2131                            args: GenericArgs::AngleBracketed {
2132                                args: ThinVec::new(),
2133                                constraints: ThinVec::new(),
2134                            },
2135                        },
2136                        kind: AssocItemConstraintKind::Equality {
2137                            term: Term::Type((**ty).clone()),
2138                        },
2139                    })
2140                    .into_iter(),
2141            ),
2142            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2143        }
2144    }
2145}
2146
2147impl<'a> IntoIterator for &'a GenericArgs {
2148    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2149    type Item = GenericArg;
2150    fn into_iter(self) -> Self::IntoIter {
2151        match self {
2152            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2153            GenericArgs::Parenthesized { inputs, .. } => {
2154                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2155                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2156            }
2157            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2158        }
2159    }
2160}
2161
2162#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2163pub(crate) struct PathSegment {
2164    pub(crate) name: Symbol,
2165    pub(crate) args: GenericArgs,
2166}
2167
2168#[derive(Clone, Debug)]
2169pub(crate) enum TypeAliasInnerType {
2170    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2171    Union { fields: Vec<Item> },
2172    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2173}
2174
2175impl TypeAliasInnerType {
2176    fn has_stripped_entries(&self) -> Option<bool> {
2177        Some(match self {
2178            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2179            Self::Union { fields } | Self::Struct { fields, .. } => {
2180                fields.iter().any(|f| f.is_stripped())
2181            }
2182        })
2183    }
2184}
2185
2186#[derive(Clone, Debug)]
2187pub(crate) struct TypeAlias {
2188    pub(crate) type_: Type,
2189    pub(crate) generics: Generics,
2190    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2191    /// to be shown directly on the typedef page.
2192    pub(crate) inner_type: Option<TypeAliasInnerType>,
2193    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2194    /// alias instead of the final type. This will always have the final type, regardless of whether
2195    /// `type_` came from HIR or from metadata.
2196    ///
2197    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2198    /// final type).
2199    pub(crate) item_type: Option<Type>,
2200}
2201
2202#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2203pub(crate) struct BareFunctionDecl {
2204    pub(crate) safety: hir::Safety,
2205    pub(crate) generic_params: Vec<GenericParamDef>,
2206    pub(crate) decl: FnDecl,
2207    pub(crate) abi: ExternAbi,
2208}
2209
2210#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2211pub(crate) struct UnsafeBinderTy {
2212    pub(crate) generic_params: Vec<GenericParamDef>,
2213    pub(crate) ty: Type,
2214}
2215
2216#[derive(Clone, Debug)]
2217pub(crate) struct Static {
2218    pub(crate) type_: Box<Type>,
2219    pub(crate) mutability: Mutability,
2220    pub(crate) expr: Option<BodyId>,
2221}
2222
2223#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2224pub(crate) struct Constant {
2225    pub(crate) generics: Generics,
2226    pub(crate) kind: ConstantKind,
2227    pub(crate) type_: Type,
2228}
2229
2230#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2231pub(crate) enum Term {
2232    Type(Type),
2233    Constant(ConstantKind),
2234}
2235
2236impl Term {
2237    pub(crate) fn ty(&self) -> Option<&Type> {
2238        if let Term::Type(ty) = self { Some(ty) } else { None }
2239    }
2240}
2241
2242impl From<Type> for Term {
2243    fn from(ty: Type) -> Self {
2244        Term::Type(ty)
2245    }
2246}
2247
2248#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2249pub(crate) enum ConstantKind {
2250    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2251    /// `BodyId`, we need to handle it on its own.
2252    ///
2253    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2254    /// by a DefId. So this field must be different from `Extern`.
2255    TyConst { expr: Box<str> },
2256    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2257    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2258    Path { path: Box<str> },
2259    /// A constant (expression) that's not an item or associated item. These are usually found
2260    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2261    /// used to define explicit discriminant values for enum variants.
2262    Anonymous { body: BodyId },
2263    /// A constant from a different crate.
2264    Extern { def_id: DefId },
2265    /// `const FOO: u32 = ...;`
2266    Local { def_id: DefId, body: BodyId },
2267    /// An inferred constant as in `[10u8; _]`.
2268    Infer,
2269}
2270
2271impl ConstantKind {
2272    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2273        match *self {
2274            ConstantKind::TyConst { ref expr } => expr.to_string(),
2275            ConstantKind::Path { ref path } => path.to_string(),
2276            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2277            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2278                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2279            }
2280            ConstantKind::Infer => "_".to_string(),
2281        }
2282    }
2283
2284    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2285        match *self {
2286            ConstantKind::TyConst { .. }
2287            | ConstantKind::Path { .. }
2288            | ConstantKind::Anonymous { .. }
2289            | ConstantKind::Infer => None,
2290            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2291                print_evaluated_const(tcx, def_id, true, true)
2292            }
2293        }
2294    }
2295
2296    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2297        match *self {
2298            ConstantKind::TyConst { .. }
2299            | ConstantKind::Extern { .. }
2300            | ConstantKind::Path { .. }
2301            | ConstantKind::Infer => false,
2302            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2303                is_literal_expr(tcx, body.hir_id)
2304            }
2305        }
2306    }
2307}
2308
2309#[derive(Clone, Debug)]
2310pub(crate) struct Impl {
2311    pub(crate) safety: hir::Safety,
2312    pub(crate) generics: Generics,
2313    pub(crate) trait_: Option<Path>,
2314    pub(crate) for_: Type,
2315    pub(crate) items: Vec<Item>,
2316    pub(crate) polarity: ty::ImplPolarity,
2317    pub(crate) kind: ImplKind,
2318    pub(crate) is_deprecated: bool,
2319}
2320
2321impl Impl {
2322    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2323        self.trait_
2324            .as_ref()
2325            .map(|t| t.def_id())
2326            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2327            .unwrap_or_default()
2328    }
2329
2330    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2331        matches!(self.polarity, ty::ImplPolarity::Negative)
2332    }
2333}
2334
2335#[derive(Clone, Debug)]
2336pub(crate) enum ImplKind {
2337    Normal,
2338    Auto,
2339    FakeVariadic,
2340    Blanket(Box<Type>),
2341}
2342
2343impl ImplKind {
2344    pub(crate) fn is_auto(&self) -> bool {
2345        matches!(self, ImplKind::Auto)
2346    }
2347
2348    pub(crate) fn is_blanket(&self) -> bool {
2349        matches!(self, ImplKind::Blanket(_))
2350    }
2351
2352    pub(crate) fn is_fake_variadic(&self) -> bool {
2353        matches!(self, ImplKind::FakeVariadic)
2354    }
2355
2356    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2357        match self {
2358            ImplKind::Blanket(ty) => Some(ty),
2359            _ => None,
2360        }
2361    }
2362}
2363
2364#[derive(Clone, Debug)]
2365pub(crate) struct Import {
2366    pub(crate) kind: ImportKind,
2367    /// The item being re-exported.
2368    pub(crate) source: ImportSource,
2369    pub(crate) should_be_displayed: bool,
2370}
2371
2372impl Import {
2373    pub(crate) fn new_simple(
2374        name: Symbol,
2375        source: ImportSource,
2376        should_be_displayed: bool,
2377    ) -> Self {
2378        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2379    }
2380
2381    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2382        Self { kind: ImportKind::Glob, source, should_be_displayed }
2383    }
2384
2385    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2386        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2387    }
2388}
2389
2390#[derive(Clone, Debug)]
2391pub(crate) enum ImportKind {
2392    // use source as str;
2393    Simple(Symbol),
2394    // use source::*;
2395    Glob,
2396}
2397
2398#[derive(Clone, Debug)]
2399pub(crate) struct ImportSource {
2400    pub(crate) path: Path,
2401    pub(crate) did: Option<DefId>,
2402}
2403
2404#[derive(Clone, Debug)]
2405pub(crate) struct Macro {
2406    pub(crate) source: String,
2407    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2408    pub(crate) macro_rules: bool,
2409}
2410
2411#[derive(Clone, Debug)]
2412pub(crate) struct ProcMacro {
2413    pub(crate) kind: MacroKind,
2414    pub(crate) helpers: Vec<Symbol>,
2415}
2416
2417/// A constraint on an associated item.
2418///
2419/// ### Examples
2420///
2421/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2422/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2423/// * the `A: Bound` in `Trait<A: Bound>`
2424/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2425/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2426/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2427#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2428pub(crate) struct AssocItemConstraint {
2429    pub(crate) assoc: PathSegment,
2430    pub(crate) kind: AssocItemConstraintKind,
2431}
2432
2433/// The kind of [associated item constraint][AssocItemConstraint].
2434#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2435pub(crate) enum AssocItemConstraintKind {
2436    Equality { term: Term },
2437    Bound { bounds: Vec<GenericBound> },
2438}
2439
2440// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2441#[cfg(target_pointer_width = "64")]
2442mod size_asserts {
2443    use rustc_data_structures::static_assert_size;
2444
2445    use super::*;
2446    // tidy-alphabetical-start
2447    static_assert_size!(Crate, 16); // frequently moved by-value
2448    static_assert_size!(DocFragment, 48);
2449    static_assert_size!(GenericArg, 32);
2450    static_assert_size!(GenericArgs, 24);
2451    static_assert_size!(GenericParamDef, 40);
2452    static_assert_size!(Generics, 16);
2453    static_assert_size!(Item, 8);
2454    static_assert_size!(ItemInner, 136);
2455    static_assert_size!(ItemKind, 48);
2456    static_assert_size!(PathSegment, 32);
2457    static_assert_size!(Type, 32);
2458    // tidy-alphabetical-end
2459}