Skip to main content

rustdoc/clean/
types.rs

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