Skip to main content

rustdoc/clean/
types.rs

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