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