Skip to main content

rustdoc/clean/
types.rs

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