[go: up one dir, main page]

rustdoc/clean/
types.rs

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