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