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