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