[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                if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr {
757                    Some(format!("#[link_section = \"{name}\"]"))
758                }
759                // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
760                // It is also used by cargo-semver-checks.
761                else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
762                    Some("#[no_mangle]".to_string())
763                } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
764                {
765                    Some(format!("#[export_name = \"{name}\"]"))
766                } else if is_json {
767                    match attr {
768                        // rustdoc-json stores this in `Item::deprecation`, so we
769                        // don't want it it `Item::attrs`.
770                        hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
771                        // We have separate pretty-printing logic for `#[repr(..)]` attributes.
772                        hir::Attribute::Parsed(AttributeKind::Repr(..)) => None,
773                        _ => Some({
774                            let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
775                            assert_eq!(s.pop(), Some('\n'));
776                            s
777                        }),
778                    }
779                } else {
780                    if !attr.has_any_name(ALLOWED_ATTRIBUTES) {
781                        return None;
782                    }
783                    Some(
784                        rustc_hir_pretty::attribute_to_string(&tcx, attr)
785                            .replace("\\\n", "")
786                            .replace('\n', "")
787                            .replace("  ", " "),
788                    )
789                }
790            })
791            .collect()
792    }
793
794    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
795        let mut attrs = self.attributes_without_repr(tcx, is_json);
796
797        if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
798            attrs.push(repr_attr);
799        }
800        attrs
801    }
802
803    /// Returns a stringified `#[repr(...)]` attribute.
804    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
805        repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
806    }
807
808    pub fn is_doc_hidden(&self) -> bool {
809        self.attrs.is_doc_hidden()
810    }
811
812    pub fn def_id(&self) -> Option<DefId> {
813        self.item_id.as_def_id()
814    }
815}
816
817pub(crate) fn repr_attributes(
818    tcx: TyCtxt<'_>,
819    cache: &Cache,
820    def_id: DefId,
821    item_type: ItemType,
822    is_json: bool,
823) -> Option<String> {
824    use rustc_abi::IntegerType;
825
826    if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
827        return None;
828    }
829    let adt = tcx.adt_def(def_id);
830    let repr = adt.repr();
831    let mut out = Vec::new();
832    if repr.c() {
833        out.push("C");
834    }
835    if repr.transparent() {
836        // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
837        // field is public in case all fields are 1-ZST fields.
838        let render_transparent = cache.document_private
839            || is_json
840            || adt
841                .all_fields()
842                .find(|field| {
843                    let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
844                    tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
845                        .is_ok_and(|layout| !layout.is_1zst())
846                })
847                .map_or_else(
848                    || adt.all_fields().any(|field| field.vis.is_public()),
849                    |field| field.vis.is_public(),
850                );
851
852        if render_transparent {
853            out.push("transparent");
854        }
855    }
856    if repr.simd() {
857        out.push("simd");
858    }
859    let pack_s;
860    if let Some(pack) = repr.pack {
861        pack_s = format!("packed({})", pack.bytes());
862        out.push(&pack_s);
863    }
864    let align_s;
865    if let Some(align) = repr.align {
866        align_s = format!("align({})", align.bytes());
867        out.push(&align_s);
868    }
869    let int_s;
870    if let Some(int) = repr.int {
871        int_s = match int {
872            IntegerType::Pointer(is_signed) => {
873                format!("{}size", if is_signed { 'i' } else { 'u' })
874            }
875            IntegerType::Fixed(size, is_signed) => {
876                format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
877            }
878        };
879        out.push(&int_s);
880    }
881    if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
882}
883
884#[derive(Clone, Debug)]
885pub(crate) enum ItemKind {
886    ExternCrateItem {
887        /// The crate's name, *not* the name it's imported as.
888        src: Option<Symbol>,
889    },
890    ImportItem(Import),
891    StructItem(Struct),
892    UnionItem(Union),
893    EnumItem(Enum),
894    FunctionItem(Box<Function>),
895    ModuleItem(Module),
896    TypeAliasItem(Box<TypeAlias>),
897    StaticItem(Static),
898    TraitItem(Box<Trait>),
899    TraitAliasItem(TraitAlias),
900    ImplItem(Box<Impl>),
901    /// A required method in a trait declaration meaning it's only a function signature.
902    RequiredMethodItem(Box<Function>),
903    /// A method in a trait impl or a provided method in a trait declaration.
904    ///
905    /// Compared to [RequiredMethodItem], it also contains a method body.
906    MethodItem(Box<Function>, Option<hir::Defaultness>),
907    StructFieldItem(Type),
908    VariantItem(Variant),
909    /// `fn`s from an extern block
910    ForeignFunctionItem(Box<Function>, hir::Safety),
911    /// `static`s from an extern block
912    ForeignStaticItem(Static, hir::Safety),
913    /// `type`s from an extern block
914    ForeignTypeItem,
915    MacroItem(Macro),
916    ProcMacroItem(ProcMacro),
917    PrimitiveItem(PrimitiveType),
918    /// A required associated constant in a trait declaration.
919    RequiredAssocConstItem(Generics, Box<Type>),
920    ConstantItem(Box<Constant>),
921    /// An associated constant in a trait declaration with provided default value.
922    ProvidedAssocConstItem(Box<Constant>),
923    /// An associated constant in an inherent impl or trait impl.
924    ImplAssocConstItem(Box<Constant>),
925    /// A required associated type in a trait declaration.
926    ///
927    /// The bounds may be non-empty if there is a `where` clause.
928    RequiredAssocTypeItem(Generics, Vec<GenericBound>),
929    /// An associated type in a trait impl or a provided one in a trait declaration.
930    AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
931    /// An item that has been stripped by a rustdoc pass
932    StrippedItem(Box<ItemKind>),
933    KeywordItem,
934}
935
936impl ItemKind {
937    /// Some items contain others such as structs (for their fields) and Enums
938    /// (for their variants). This method returns those contained items.
939    pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
940        match self {
941            StructItem(s) => s.fields.iter(),
942            UnionItem(u) => u.fields.iter(),
943            VariantItem(v) => match &v.kind {
944                VariantKind::CLike => [].iter(),
945                VariantKind::Tuple(t) => t.iter(),
946                VariantKind::Struct(s) => s.fields.iter(),
947            },
948            EnumItem(e) => e.variants.iter(),
949            TraitItem(t) => t.items.iter(),
950            ImplItem(i) => i.items.iter(),
951            ModuleItem(m) => m.items.iter(),
952            ExternCrateItem { .. }
953            | ImportItem(_)
954            | FunctionItem(_)
955            | TypeAliasItem(_)
956            | StaticItem(_)
957            | ConstantItem(_)
958            | TraitAliasItem(_)
959            | RequiredMethodItem(_)
960            | MethodItem(_, _)
961            | StructFieldItem(_)
962            | ForeignFunctionItem(_, _)
963            | ForeignStaticItem(_, _)
964            | ForeignTypeItem
965            | MacroItem(_)
966            | ProcMacroItem(_)
967            | PrimitiveItem(_)
968            | RequiredAssocConstItem(..)
969            | ProvidedAssocConstItem(..)
970            | ImplAssocConstItem(..)
971            | RequiredAssocTypeItem(..)
972            | AssocTypeItem(..)
973            | StrippedItem(_)
974            | KeywordItem => [].iter(),
975        }
976    }
977
978    /// Returns `true` if this item does not appear inside an impl block.
979    pub(crate) fn is_non_assoc(&self) -> bool {
980        matches!(
981            self,
982            StructItem(_)
983                | UnionItem(_)
984                | EnumItem(_)
985                | TraitItem(_)
986                | ModuleItem(_)
987                | ExternCrateItem { .. }
988                | FunctionItem(_)
989                | TypeAliasItem(_)
990                | StaticItem(_)
991                | ConstantItem(_)
992                | TraitAliasItem(_)
993                | ForeignFunctionItem(_, _)
994                | ForeignStaticItem(_, _)
995                | ForeignTypeItem
996                | MacroItem(_)
997                | ProcMacroItem(_)
998                | PrimitiveItem(_)
999        )
1000    }
1001}
1002
1003#[derive(Clone, Debug)]
1004pub(crate) struct Module {
1005    pub(crate) items: Vec<Item>,
1006    pub(crate) span: Span,
1007}
1008
1009pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1010    attrs: I,
1011    name: Symbol,
1012) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1013    attrs
1014        .into_iter()
1015        .filter(move |attr| attr.has_name(name))
1016        .filter_map(ast::attr::AttributeExt::meta_item_list)
1017        .flatten()
1018}
1019
1020pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1021    attrs: I,
1022    tcx: TyCtxt<'_>,
1023    hidden_cfg: &FxHashSet<Cfg>,
1024) -> Option<Arc<Cfg>> {
1025    let doc_cfg_active = tcx.features().doc_cfg();
1026    let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1027
1028    fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1029        let mut iter = it.into_iter();
1030        let item = iter.next()?;
1031        if iter.next().is_some() {
1032            return None;
1033        }
1034        Some(item)
1035    }
1036
1037    let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1038        let mut doc_cfg = attrs
1039            .clone()
1040            .filter(|attr| attr.has_name(sym::doc))
1041            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1042            .filter(|attr| attr.has_name(sym::cfg))
1043            .peekable();
1044        if doc_cfg.peek().is_some() && doc_cfg_active {
1045            let sess = tcx.sess;
1046
1047            doc_cfg.fold(Cfg::True, |mut cfg, item| {
1048                if let Some(cfg_mi) =
1049                    item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1050                {
1051                    match Cfg::parse(cfg_mi) {
1052                        Ok(new_cfg) => cfg &= new_cfg,
1053                        Err(e) => {
1054                            sess.dcx().span_err(e.span, e.msg);
1055                        }
1056                    }
1057                }
1058                cfg
1059            })
1060        } else if doc_auto_cfg_active {
1061            // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1062            // `doc(cfg())` overrides `cfg()`).
1063            attrs
1064                .clone()
1065                .filter(|attr| attr.has_name(sym::cfg_trace))
1066                .filter_map(|attr| single(attr.meta_item_list()?))
1067                .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1068                .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1069        } else {
1070            Cfg::True
1071        }
1072    } else {
1073        Cfg::True
1074    };
1075
1076    // treat #[target_feature(enable = "feat")] attributes as if they were
1077    // #[doc(cfg(target_feature = "feat"))] attributes as well
1078    for attr in hir_attr_lists(attrs, sym::target_feature) {
1079        if attr.has_name(sym::enable) && attr.value_str().is_some() {
1080            // Clone `enable = "feat"`, change to `target_feature = "feat"`.
1081            // Unwrap is safe because `value_str` succeeded above.
1082            let mut meta = attr.meta_item().unwrap().clone();
1083            meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1084
1085            if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1086                cfg &= feat_cfg;
1087            }
1088        }
1089    }
1090
1091    if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1092}
1093
1094pub(crate) trait NestedAttributesExt {
1095    /// Returns `true` if the attribute list contains a specific `word`
1096    fn has_word(self, word: Symbol) -> bool
1097    where
1098        Self: Sized,
1099    {
1100        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1101    }
1102
1103    /// Returns `Some(attr)` if the attribute list contains 'attr'
1104    /// corresponding to a specific `word`
1105    fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1106}
1107
1108impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1109    fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1110        self.find(|attr| attr.is_word() && attr.has_name(word))
1111    }
1112}
1113
1114/// A link that has not yet been rendered.
1115///
1116/// This link will be turned into a rendered link by [`Item::links`].
1117#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1118pub(crate) struct ItemLink {
1119    /// The original link written in the markdown
1120    pub(crate) link: Box<str>,
1121    /// The link text displayed in the HTML.
1122    ///
1123    /// This may not be the same as `link` if there was a disambiguator
1124    /// in an intra-doc link (e.g. \[`fn@f`\])
1125    pub(crate) link_text: Box<str>,
1126    /// The `DefId` of the Item whose **HTML Page** contains the item being
1127    /// linked to. This will be different to `item_id` on item's that don't
1128    /// have their own page, such as struct fields and enum variants.
1129    pub(crate) page_id: DefId,
1130    /// The url fragment to append to the link
1131    pub(crate) fragment: Option<UrlFragment>,
1132}
1133
1134pub struct RenderedLink {
1135    /// The text the link was original written as.
1136    ///
1137    /// This could potentially include disambiguators and backticks.
1138    pub(crate) original_text: Box<str>,
1139    /// The text to display in the HTML
1140    pub(crate) new_text: Box<str>,
1141    /// The URL to put in the `href`
1142    pub(crate) href: String,
1143    /// The tooltip.
1144    pub(crate) tooltip: String,
1145}
1146
1147/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1148/// as well as doc comments.
1149#[derive(Clone, Debug, Default)]
1150pub(crate) struct Attributes {
1151    pub(crate) doc_strings: Vec<DocFragment>,
1152    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1153}
1154
1155impl Attributes {
1156    pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1157        hir_attr_lists(&self.other_attrs[..], name)
1158    }
1159
1160    pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1161        for attr in &self.other_attrs {
1162            if !attr.has_name(sym::doc) {
1163                continue;
1164            }
1165
1166            if let Some(items) = attr.meta_item_list()
1167                && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1168            {
1169                return true;
1170            }
1171        }
1172
1173        false
1174    }
1175
1176    pub(crate) fn is_doc_hidden(&self) -> bool {
1177        self.has_doc_flag(sym::hidden)
1178    }
1179
1180    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1181        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1182    }
1183
1184    pub(crate) fn from_hir_with_additional(
1185        attrs: &[hir::Attribute],
1186        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1187    ) -> Attributes {
1188        // Additional documentation should be shown before the original documentation.
1189        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1190        let attrs2 = attrs.iter().map(|attr| (attr, None));
1191        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1192    }
1193
1194    pub(crate) fn from_hir_iter<'a>(
1195        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1196        doc_only: bool,
1197    ) -> Attributes {
1198        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1199        Attributes { doc_strings, other_attrs }
1200    }
1201
1202    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1203    pub(crate) fn doc_value(&self) -> String {
1204        self.opt_doc_value().unwrap_or_default()
1205    }
1206
1207    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1208    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1209    /// documentation but it is empty (e.g. `#[doc = ""]`).
1210    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1211        (!self.doc_strings.is_empty()).then(|| {
1212            let mut res = String::new();
1213            for frag in &self.doc_strings {
1214                add_doc_fragment(&mut res, frag);
1215            }
1216            res.pop();
1217            res
1218        })
1219    }
1220
1221    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1222        let mut aliases = FxIndexSet::default();
1223
1224        for attr in
1225            hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1226        {
1227            if let Some(values) = attr.meta_item_list() {
1228                for l in values {
1229                    if let Some(lit) = l.lit()
1230                        && let ast::LitKind::Str(s, _) = lit.kind
1231                    {
1232                        aliases.insert(s);
1233                    }
1234                }
1235            } else if let Some(value) = attr.value_str() {
1236                aliases.insert(value);
1237            }
1238        }
1239        aliases.into_iter().collect::<Vec<_>>().into()
1240    }
1241}
1242
1243#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1244pub(crate) enum GenericBound {
1245    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1246    Outlives(Lifetime),
1247    /// `use<'a, T>` precise-capturing bound syntax
1248    Use(Vec<PreciseCapturingArg>),
1249}
1250
1251impl GenericBound {
1252    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1253        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1254    }
1255
1256    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1257        Self::sized_with(
1258            cx,
1259            hir::TraitBoundModifiers {
1260                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1261                constness: hir::BoundConstness::Never,
1262            },
1263        )
1264    }
1265
1266    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1267        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1268        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1269        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1270        inline::record_extern_fqn(cx, did, ItemType::Trait);
1271        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1272    }
1273
1274    pub(crate) fn is_trait_bound(&self) -> bool {
1275        matches!(self, Self::TraitBound(..))
1276    }
1277
1278    pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1279        self.is_bounded_by_lang_item(cx, LangItem::Sized)
1280    }
1281
1282    pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1283        self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1284    }
1285
1286    fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1287        if let GenericBound::TraitBound(
1288            PolyTrait { ref trait_, .. },
1289            rustc_hir::TraitBoundModifiers::NONE,
1290        ) = *self
1291            && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1292        {
1293            return true;
1294        }
1295        false
1296    }
1297
1298    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1299        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1300            Some(trait_.clone())
1301        } else {
1302            None
1303        }
1304    }
1305}
1306
1307#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1308pub(crate) struct Lifetime(pub Symbol);
1309
1310impl Lifetime {
1311    pub(crate) fn statik() -> Lifetime {
1312        Lifetime(kw::StaticLifetime)
1313    }
1314
1315    pub(crate) fn elided() -> Lifetime {
1316        Lifetime(kw::UnderscoreLifetime)
1317    }
1318}
1319
1320#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1321pub(crate) enum PreciseCapturingArg {
1322    Lifetime(Lifetime),
1323    Param(Symbol),
1324}
1325
1326impl PreciseCapturingArg {
1327    pub(crate) fn name(self) -> Symbol {
1328        match self {
1329            PreciseCapturingArg::Lifetime(lt) => lt.0,
1330            PreciseCapturingArg::Param(param) => param,
1331        }
1332    }
1333}
1334
1335#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1336pub(crate) enum WherePredicate {
1337    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1338    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1339    EqPredicate { lhs: QPathData, rhs: Term },
1340}
1341
1342impl WherePredicate {
1343    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1344        match self {
1345            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1346            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1347            _ => None,
1348        }
1349    }
1350}
1351
1352#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1353pub(crate) enum GenericParamDefKind {
1354    Lifetime { outlives: ThinVec<Lifetime> },
1355    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1356    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1357    Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1358}
1359
1360impl GenericParamDefKind {
1361    pub(crate) fn is_type(&self) -> bool {
1362        matches!(self, GenericParamDefKind::Type { .. })
1363    }
1364}
1365
1366#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1367pub(crate) struct GenericParamDef {
1368    pub(crate) name: Symbol,
1369    pub(crate) def_id: DefId,
1370    pub(crate) kind: GenericParamDefKind,
1371}
1372
1373impl GenericParamDef {
1374    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1375        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1376    }
1377
1378    pub(crate) fn is_synthetic_param(&self) -> bool {
1379        match self.kind {
1380            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1381            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1382        }
1383    }
1384
1385    pub(crate) fn is_type(&self) -> bool {
1386        self.kind.is_type()
1387    }
1388
1389    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1390        match self.kind {
1391            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1392            _ => None,
1393        }
1394    }
1395}
1396
1397// maybe use a Generic enum and use Vec<Generic>?
1398#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1399pub(crate) struct Generics {
1400    pub(crate) params: ThinVec<GenericParamDef>,
1401    pub(crate) where_predicates: ThinVec<WherePredicate>,
1402}
1403
1404impl Generics {
1405    pub(crate) fn is_empty(&self) -> bool {
1406        self.params.is_empty() && self.where_predicates.is_empty()
1407    }
1408}
1409
1410#[derive(Clone, Debug)]
1411pub(crate) struct Function {
1412    pub(crate) decl: FnDecl,
1413    pub(crate) generics: Generics,
1414}
1415
1416#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1417pub(crate) struct FnDecl {
1418    pub(crate) inputs: Vec<Parameter>,
1419    pub(crate) output: Type,
1420    pub(crate) c_variadic: bool,
1421}
1422
1423impl FnDecl {
1424    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1425        self.inputs.first().and_then(|v| v.to_receiver())
1426    }
1427}
1428
1429/// A function parameter.
1430#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1431pub(crate) struct Parameter {
1432    pub(crate) name: Option<Symbol>,
1433    pub(crate) type_: Type,
1434    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1435    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1436    pub(crate) is_const: bool,
1437}
1438
1439impl Parameter {
1440    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1441        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1442    }
1443}
1444
1445#[derive(Clone, Debug)]
1446pub(crate) struct Trait {
1447    pub(crate) def_id: DefId,
1448    pub(crate) items: Vec<Item>,
1449    pub(crate) generics: Generics,
1450    pub(crate) bounds: Vec<GenericBound>,
1451}
1452
1453impl Trait {
1454    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1455        tcx.trait_is_auto(self.def_id)
1456    }
1457    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1458        tcx.is_doc_notable_trait(self.def_id)
1459    }
1460    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1461        tcx.trait_def(self.def_id).safety
1462    }
1463    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1464        tcx.is_dyn_compatible(self.def_id)
1465    }
1466}
1467
1468#[derive(Clone, Debug)]
1469pub(crate) struct TraitAlias {
1470    pub(crate) generics: Generics,
1471    pub(crate) bounds: Vec<GenericBound>,
1472}
1473
1474/// A trait reference, which may have higher ranked lifetimes.
1475#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1476pub(crate) struct PolyTrait {
1477    pub(crate) trait_: Path,
1478    pub(crate) generic_params: Vec<GenericParamDef>,
1479}
1480
1481/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1482#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1483pub(crate) enum Type {
1484    /// A named type, which could be a trait.
1485    ///
1486    /// This is mostly Rustdoc's version of [`hir::Path`].
1487    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1488    Path {
1489        path: Path,
1490    },
1491    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1492    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1493    /// A type parameter.
1494    Generic(Symbol),
1495    /// The `Self` type.
1496    SelfTy,
1497    /// A primitive (aka, builtin) type.
1498    Primitive(PrimitiveType),
1499    /// A function pointer: `extern "ABI" fn(...) -> ...`
1500    BareFunction(Box<BareFunctionDecl>),
1501    /// A tuple type: `(i32, &str)`.
1502    Tuple(Vec<Type>),
1503    /// A slice type (does *not* include the `&`): `[i32]`
1504    Slice(Box<Type>),
1505    /// An array type.
1506    ///
1507    /// The `String` field is a stringified version of the array's length parameter.
1508    Array(Box<Type>, Box<str>),
1509    Pat(Box<Type>, Box<str>),
1510    /// A raw pointer type: `*const i32`, `*mut i32`
1511    RawPointer(Mutability, Box<Type>),
1512    /// A reference type: `&i32`, `&'a mut Foo`
1513    BorrowedRef {
1514        lifetime: Option<Lifetime>,
1515        mutability: Mutability,
1516        type_: Box<Type>,
1517    },
1518
1519    /// A qualified path to an associated item: `<Type as Trait>::Name`
1520    QPath(Box<QPathData>),
1521
1522    /// A type that is inferred: `_`
1523    Infer,
1524
1525    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1526    ImplTrait(Vec<GenericBound>),
1527
1528    UnsafeBinder(Box<UnsafeBinderTy>),
1529}
1530
1531impl Type {
1532    /// When comparing types for equality, it can help to ignore `&` wrapping.
1533    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1534        let mut result = self;
1535        while let Type::BorrowedRef { type_, .. } = result {
1536            result = type_;
1537        }
1538        result
1539    }
1540
1541    pub(crate) fn is_borrowed_ref(&self) -> bool {
1542        matches!(self, Type::BorrowedRef { .. })
1543    }
1544
1545    fn is_type_alias(&self) -> bool {
1546        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1547    }
1548
1549    /// Check if two types are "the same" for documentation purposes.
1550    ///
1551    /// This is different from `Eq`, because it knows that things like
1552    /// `Placeholder` are possible matches for everything.
1553    ///
1554    /// This relation is not commutative when generics are involved:
1555    ///
1556    /// ```ignore(private)
1557    /// # // see types/tests.rs:is_same_generic for the real test
1558    /// use rustdoc::format::cache::Cache;
1559    /// use rustdoc::clean::types::{Type, PrimitiveType};
1560    /// let cache = Cache::new(false);
1561    /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
1562    /// let unit = Type::Primitive(PrimitiveType::Unit);
1563    /// assert!(!generic.is_same(&unit, &cache));
1564    /// assert!(unit.is_same(&generic, &cache));
1565    /// ```
1566    ///
1567    /// An owned type is also the same as its borrowed variants (this is commutative),
1568    /// but `&T` is not the same as `&mut T`.
1569    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1570        // Strip the references so that it can compare the actual types, unless both are references.
1571        // If both are references, leave them alone and compare the mutabilities later.
1572        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1573            (self.without_borrowed_ref(), other.without_borrowed_ref())
1574        } else {
1575            (self, other)
1576        };
1577
1578        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1579        // so we just assume they are equal.
1580        // This is only remotely acceptable because we were previously
1581        // assuming all types were equal when used
1582        // as a generic parameter of a type in `Deref::Target`.
1583        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1584            return true;
1585        }
1586
1587        match (self_cleared, other_cleared) {
1588            // Recursive cases.
1589            (Type::Tuple(a), Type::Tuple(b)) => {
1590                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1591            }
1592            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1593            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1594            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1595                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1596            }
1597            (
1598                Type::BorrowedRef { mutability, type_, .. },
1599                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1600            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1601            // Placeholders are equal to all other types.
1602            (Type::Infer, _) | (_, Type::Infer) => true,
1603            // Generics match everything on the right, but not on the left.
1604            // If both sides are generic, this returns true.
1605            (_, Type::Generic(_)) => true,
1606            (Type::Generic(_), _) => false,
1607            // `Self` only matches itself.
1608            (Type::SelfTy, Type::SelfTy) => true,
1609            // Paths account for both the path itself and its generics.
1610            (Type::Path { path: a }, Type::Path { path: b }) => {
1611                a.def_id() == b.def_id()
1612                    && a.generics()
1613                        .zip(b.generics())
1614                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1615                        .unwrap_or(true)
1616            }
1617            // Other cases, such as primitives, just use recursion.
1618            (a, b) => a
1619                .def_id(cache)
1620                .and_then(|a| Some((a, b.def_id(cache)?)))
1621                .map(|(a, b)| a == b)
1622                .unwrap_or(false),
1623        }
1624    }
1625
1626    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1627        match *self {
1628            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1629            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1630            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1631            Tuple(ref tys) => {
1632                if tys.is_empty() {
1633                    Some(PrimitiveType::Unit)
1634                } else {
1635                    Some(PrimitiveType::Tuple)
1636                }
1637            }
1638            RawPointer(..) => Some(PrimitiveType::RawPointer),
1639            BareFunction(..) => Some(PrimitiveType::Fn),
1640            _ => None,
1641        }
1642    }
1643
1644    /// Returns the sugared return type for an async function.
1645    ///
1646    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1647    /// will return `i32`.
1648    ///
1649    /// # Panics
1650    ///
1651    /// This function will panic if the return type does not match the expected sugaring for async
1652    /// functions.
1653    pub(crate) fn sugared_async_return_type(self) -> Type {
1654        if let Type::ImplTrait(mut v) = self
1655            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1656            && let Some(segment) = trait_.segments.pop()
1657            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1658            && let Some(constraint) = constraints.pop()
1659            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1660            && let Term::Type(ty) = term
1661        {
1662            ty
1663        } else {
1664            panic!("unexpected async fn return type")
1665        }
1666    }
1667
1668    /// Checks if this is a `T::Name` path for an associated type.
1669    pub(crate) fn is_assoc_ty(&self) -> bool {
1670        match self {
1671            Type::Path { path, .. } => path.is_assoc_ty(),
1672            _ => false,
1673        }
1674    }
1675
1676    pub(crate) fn is_self_type(&self) -> bool {
1677        matches!(*self, Type::SelfTy)
1678    }
1679
1680    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1681        match self {
1682            Type::Path { path, .. } => path.generic_args(),
1683            _ => None,
1684        }
1685    }
1686
1687    pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
1688        match self {
1689            Type::Path { path, .. } => path.generics(),
1690            _ => None,
1691        }
1692    }
1693
1694    pub(crate) fn is_full_generic(&self) -> bool {
1695        matches!(self, Type::Generic(_))
1696    }
1697
1698    pub(crate) fn is_unit(&self) -> bool {
1699        matches!(self, Type::Tuple(v) if v.is_empty())
1700    }
1701
1702    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1703    ///
1704    /// [clean]: crate::clean
1705    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1706        let t: PrimitiveType = match self {
1707            Type::Path { path } => return Some(path.def_id()),
1708            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1709            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1710            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1711            BorrowedRef { type_, .. } => return type_.def_id(cache),
1712            Tuple(tys) => {
1713                if tys.is_empty() {
1714                    PrimitiveType::Unit
1715                } else {
1716                    PrimitiveType::Tuple
1717                }
1718            }
1719            BareFunction(..) => PrimitiveType::Fn,
1720            Slice(..) => PrimitiveType::Slice,
1721            Array(..) => PrimitiveType::Array,
1722            Type::Pat(..) => PrimitiveType::Pat,
1723            RawPointer(..) => PrimitiveType::RawPointer,
1724            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1725            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1726        };
1727        Primitive(t).def_id(cache)
1728    }
1729}
1730
1731#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1732pub(crate) struct QPathData {
1733    pub assoc: PathSegment,
1734    pub self_type: Type,
1735    /// FIXME: compute this field on demand.
1736    pub should_fully_qualify: bool,
1737    pub trait_: Option<Path>,
1738}
1739
1740/// A primitive (aka, builtin) type.
1741///
1742/// This represents things like `i32`, `str`, etc.
1743///
1744/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1745/// paths, like [`Self::Unit`].
1746#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1747pub(crate) enum PrimitiveType {
1748    Isize,
1749    I8,
1750    I16,
1751    I32,
1752    I64,
1753    I128,
1754    Usize,
1755    U8,
1756    U16,
1757    U32,
1758    U64,
1759    U128,
1760    F16,
1761    F32,
1762    F64,
1763    F128,
1764    Char,
1765    Bool,
1766    Str,
1767    Slice,
1768    Array,
1769    Pat,
1770    Tuple,
1771    Unit,
1772    RawPointer,
1773    Reference,
1774    Fn,
1775    Never,
1776}
1777
1778type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1779impl PrimitiveType {
1780    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1781        use ast::{FloatTy, IntTy, UintTy};
1782        match prim {
1783            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1784            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1785            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1786            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1787            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1788            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1789            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1790            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1791            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1792            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1793            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1794            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1795            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1796            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1797            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1798            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1799            hir::PrimTy::Str => PrimitiveType::Str,
1800            hir::PrimTy::Bool => PrimitiveType::Bool,
1801            hir::PrimTy::Char => PrimitiveType::Char,
1802        }
1803    }
1804
1805    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1806        match s {
1807            sym::isize => Some(PrimitiveType::Isize),
1808            sym::i8 => Some(PrimitiveType::I8),
1809            sym::i16 => Some(PrimitiveType::I16),
1810            sym::i32 => Some(PrimitiveType::I32),
1811            sym::i64 => Some(PrimitiveType::I64),
1812            sym::i128 => Some(PrimitiveType::I128),
1813            sym::usize => Some(PrimitiveType::Usize),
1814            sym::u8 => Some(PrimitiveType::U8),
1815            sym::u16 => Some(PrimitiveType::U16),
1816            sym::u32 => Some(PrimitiveType::U32),
1817            sym::u64 => Some(PrimitiveType::U64),
1818            sym::u128 => Some(PrimitiveType::U128),
1819            sym::bool => Some(PrimitiveType::Bool),
1820            sym::char => Some(PrimitiveType::Char),
1821            sym::str => Some(PrimitiveType::Str),
1822            sym::f16 => Some(PrimitiveType::F16),
1823            sym::f32 => Some(PrimitiveType::F32),
1824            sym::f64 => Some(PrimitiveType::F64),
1825            sym::f128 => Some(PrimitiveType::F128),
1826            sym::array => Some(PrimitiveType::Array),
1827            sym::slice => Some(PrimitiveType::Slice),
1828            sym::tuple => Some(PrimitiveType::Tuple),
1829            sym::unit => Some(PrimitiveType::Unit),
1830            sym::pointer => Some(PrimitiveType::RawPointer),
1831            sym::reference => Some(PrimitiveType::Reference),
1832            kw::Fn => Some(PrimitiveType::Fn),
1833            sym::never => Some(PrimitiveType::Never),
1834            _ => None,
1835        }
1836    }
1837
1838    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1839        use PrimitiveType::*;
1840        use ty::{FloatTy, IntTy, UintTy};
1841        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1842
1843        let single = |x| iter::once(x).collect();
1844        CELL.get_or_init(move || {
1845            map! {
1846                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1847                I8 => single(SimplifiedType::Int(IntTy::I8)),
1848                I16 => single(SimplifiedType::Int(IntTy::I16)),
1849                I32 => single(SimplifiedType::Int(IntTy::I32)),
1850                I64 => single(SimplifiedType::Int(IntTy::I64)),
1851                I128 => single(SimplifiedType::Int(IntTy::I128)),
1852                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1853                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1854                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1855                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1856                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1857                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1858                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1859                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1860                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1861                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1862                Str => single(SimplifiedType::Str),
1863                Bool => single(SimplifiedType::Bool),
1864                Char => single(SimplifiedType::Char),
1865                Array => single(SimplifiedType::Array),
1866                Slice => single(SimplifiedType::Slice),
1867                // FIXME: If we ever add an inherent impl for tuples
1868                // with different lengths, they won't show in rustdoc.
1869                //
1870                // Either manually update this arrayvec at this point
1871                // or start with a more complex refactoring.
1872                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1873                Unit => single(SimplifiedType::Tuple(0)),
1874                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1875                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1876                // FIXME: This will be wrong if we ever add inherent impls
1877                // for function pointers.
1878                Fn => single(SimplifiedType::Function(1)),
1879                Never => single(SimplifiedType::Never),
1880            }
1881        })
1882    }
1883
1884    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1885        Self::simplified_types()
1886            .get(self)
1887            .into_iter()
1888            .flatten()
1889            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1890            .copied()
1891    }
1892
1893    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1894        Self::simplified_types()
1895            .values()
1896            .flatten()
1897            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1898            .copied()
1899    }
1900
1901    pub(crate) fn as_sym(&self) -> Symbol {
1902        use PrimitiveType::*;
1903        match self {
1904            Isize => sym::isize,
1905            I8 => sym::i8,
1906            I16 => sym::i16,
1907            I32 => sym::i32,
1908            I64 => sym::i64,
1909            I128 => sym::i128,
1910            Usize => sym::usize,
1911            U8 => sym::u8,
1912            U16 => sym::u16,
1913            U32 => sym::u32,
1914            U64 => sym::u64,
1915            U128 => sym::u128,
1916            F16 => sym::f16,
1917            F32 => sym::f32,
1918            F64 => sym::f64,
1919            F128 => sym::f128,
1920            Str => sym::str,
1921            Bool => sym::bool,
1922            Char => sym::char,
1923            Array => sym::array,
1924            Pat => sym::pat,
1925            Slice => sym::slice,
1926            Tuple => sym::tuple,
1927            Unit => sym::unit,
1928            RawPointer => sym::pointer,
1929            Reference => sym::reference,
1930            Fn => kw::Fn,
1931            Never => sym::never,
1932        }
1933    }
1934
1935    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1936    /// Panics if there is no such module.
1937    ///
1938    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1939    /// primitives defined in `core`,
1940    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1941    /// will be picked.
1942    ///
1943    /// In particular, if a crate depends on both `std` and another crate that also defines
1944    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1945    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1946    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1947        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1948        PRIMITIVE_LOCATIONS.get_or_init(|| {
1949            let mut primitive_locations = FxIndexMap::default();
1950            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1951            // This is a degenerate case that I don't plan to support.
1952            for &crate_num in tcx.crates(()) {
1953                let e = ExternalCrate { crate_num };
1954                let crate_name = e.name(tcx);
1955                debug!(?crate_num, ?crate_name);
1956                for (def_id, prim) in e.primitives(tcx) {
1957                    // HACK: try to link to std instead where possible
1958                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1959                        continue;
1960                    }
1961                    primitive_locations.insert(prim, def_id);
1962                }
1963            }
1964            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1965            for (def_id, prim) in local_primitives {
1966                primitive_locations.insert(prim, def_id);
1967            }
1968            primitive_locations
1969        })
1970    }
1971}
1972
1973impl From<ast::IntTy> for PrimitiveType {
1974    fn from(int_ty: ast::IntTy) -> PrimitiveType {
1975        match int_ty {
1976            ast::IntTy::Isize => PrimitiveType::Isize,
1977            ast::IntTy::I8 => PrimitiveType::I8,
1978            ast::IntTy::I16 => PrimitiveType::I16,
1979            ast::IntTy::I32 => PrimitiveType::I32,
1980            ast::IntTy::I64 => PrimitiveType::I64,
1981            ast::IntTy::I128 => PrimitiveType::I128,
1982        }
1983    }
1984}
1985
1986impl From<ast::UintTy> for PrimitiveType {
1987    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1988        match uint_ty {
1989            ast::UintTy::Usize => PrimitiveType::Usize,
1990            ast::UintTy::U8 => PrimitiveType::U8,
1991            ast::UintTy::U16 => PrimitiveType::U16,
1992            ast::UintTy::U32 => PrimitiveType::U32,
1993            ast::UintTy::U64 => PrimitiveType::U64,
1994            ast::UintTy::U128 => PrimitiveType::U128,
1995        }
1996    }
1997}
1998
1999impl From<ast::FloatTy> for PrimitiveType {
2000    fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2001        match float_ty {
2002            ast::FloatTy::F16 => PrimitiveType::F16,
2003            ast::FloatTy::F32 => PrimitiveType::F32,
2004            ast::FloatTy::F64 => PrimitiveType::F64,
2005            ast::FloatTy::F128 => PrimitiveType::F128,
2006        }
2007    }
2008}
2009
2010impl From<ty::IntTy> for PrimitiveType {
2011    fn from(int_ty: ty::IntTy) -> PrimitiveType {
2012        match int_ty {
2013            ty::IntTy::Isize => PrimitiveType::Isize,
2014            ty::IntTy::I8 => PrimitiveType::I8,
2015            ty::IntTy::I16 => PrimitiveType::I16,
2016            ty::IntTy::I32 => PrimitiveType::I32,
2017            ty::IntTy::I64 => PrimitiveType::I64,
2018            ty::IntTy::I128 => PrimitiveType::I128,
2019        }
2020    }
2021}
2022
2023impl From<ty::UintTy> for PrimitiveType {
2024    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2025        match uint_ty {
2026            ty::UintTy::Usize => PrimitiveType::Usize,
2027            ty::UintTy::U8 => PrimitiveType::U8,
2028            ty::UintTy::U16 => PrimitiveType::U16,
2029            ty::UintTy::U32 => PrimitiveType::U32,
2030            ty::UintTy::U64 => PrimitiveType::U64,
2031            ty::UintTy::U128 => PrimitiveType::U128,
2032        }
2033    }
2034}
2035
2036impl From<ty::FloatTy> for PrimitiveType {
2037    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2038        match float_ty {
2039            ty::FloatTy::F16 => PrimitiveType::F16,
2040            ty::FloatTy::F32 => PrimitiveType::F32,
2041            ty::FloatTy::F64 => PrimitiveType::F64,
2042            ty::FloatTy::F128 => PrimitiveType::F128,
2043        }
2044    }
2045}
2046
2047impl From<hir::PrimTy> for PrimitiveType {
2048    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2049        match prim_ty {
2050            hir::PrimTy::Int(int_ty) => int_ty.into(),
2051            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2052            hir::PrimTy::Float(float_ty) => float_ty.into(),
2053            hir::PrimTy::Str => PrimitiveType::Str,
2054            hir::PrimTy::Bool => PrimitiveType::Bool,
2055            hir::PrimTy::Char => PrimitiveType::Char,
2056        }
2057    }
2058}
2059
2060#[derive(Clone, Debug)]
2061pub(crate) struct Struct {
2062    pub(crate) ctor_kind: Option<CtorKind>,
2063    pub(crate) generics: Generics,
2064    pub(crate) fields: ThinVec<Item>,
2065}
2066
2067impl Struct {
2068    pub(crate) fn has_stripped_entries(&self) -> bool {
2069        self.fields.iter().any(|f| f.is_stripped())
2070    }
2071}
2072
2073#[derive(Clone, Debug)]
2074pub(crate) struct Union {
2075    pub(crate) generics: Generics,
2076    pub(crate) fields: Vec<Item>,
2077}
2078
2079impl Union {
2080    pub(crate) fn has_stripped_entries(&self) -> bool {
2081        self.fields.iter().any(|f| f.is_stripped())
2082    }
2083}
2084
2085/// This is a more limited form of the standard Struct, different in that
2086/// it lacks the things most items have (name, id, parameterization). Found
2087/// only as a variant in an enum.
2088#[derive(Clone, Debug)]
2089pub(crate) struct VariantStruct {
2090    pub(crate) fields: ThinVec<Item>,
2091}
2092
2093impl VariantStruct {
2094    pub(crate) fn has_stripped_entries(&self) -> bool {
2095        self.fields.iter().any(|f| f.is_stripped())
2096    }
2097}
2098
2099#[derive(Clone, Debug)]
2100pub(crate) struct Enum {
2101    pub(crate) variants: IndexVec<VariantIdx, Item>,
2102    pub(crate) generics: Generics,
2103}
2104
2105impl Enum {
2106    pub(crate) fn has_stripped_entries(&self) -> bool {
2107        self.variants.iter().any(|f| f.is_stripped())
2108    }
2109
2110    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2111        self.variants.iter().filter(|v| !v.is_stripped())
2112    }
2113}
2114
2115#[derive(Clone, Debug)]
2116pub(crate) struct Variant {
2117    pub kind: VariantKind,
2118    pub discriminant: Option<Discriminant>,
2119}
2120
2121#[derive(Clone, Debug)]
2122pub(crate) enum VariantKind {
2123    CLike,
2124    Tuple(ThinVec<Item>),
2125    Struct(VariantStruct),
2126}
2127
2128impl Variant {
2129    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2130        match &self.kind {
2131            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2132            VariantKind::CLike | VariantKind::Tuple(_) => None,
2133        }
2134    }
2135}
2136
2137#[derive(Clone, Debug)]
2138pub(crate) struct Discriminant {
2139    // In the case of cross crate re-exports, we don't have the necessary information
2140    // to reconstruct the expression of the discriminant, only the value.
2141    pub(super) expr: Option<BodyId>,
2142    pub(super) value: DefId,
2143}
2144
2145impl Discriminant {
2146    /// Will be `None` in the case of cross-crate reexports, and may be
2147    /// simplified
2148    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2149        self.expr
2150            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2151    }
2152    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2153        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2154    }
2155}
2156
2157/// Small wrapper around [`rustc_span::Span`] that adds helper methods
2158/// and enforces calling [`rustc_span::Span::source_callsite()`].
2159#[derive(Copy, Clone, Debug)]
2160pub(crate) struct Span(rustc_span::Span);
2161
2162impl Span {
2163    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
2164    /// span will be updated to point to the macro invocation instead of the macro definition.
2165    ///
2166    /// (See rust-lang/rust#39726)
2167    pub(crate) fn new(sp: rustc_span::Span) -> Self {
2168        Self(sp.source_callsite())
2169    }
2170
2171    pub(crate) fn inner(&self) -> rustc_span::Span {
2172        self.0
2173    }
2174
2175    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2176        sess.source_map().span_to_filename(self.0)
2177    }
2178
2179    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2180        sess.source_map().lookup_char_pos(self.0.lo())
2181    }
2182
2183    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2184        sess.source_map().lookup_char_pos(self.0.hi())
2185    }
2186
2187    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2188        // FIXME: is there a time when the lo and hi crate would be different?
2189        self.lo(sess).file.cnum
2190    }
2191}
2192
2193#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2194pub(crate) struct Path {
2195    pub(crate) res: Res,
2196    pub(crate) segments: ThinVec<PathSegment>,
2197}
2198
2199impl Path {
2200    pub(crate) fn def_id(&self) -> DefId {
2201        self.res.def_id()
2202    }
2203
2204    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2205        self.segments.last().map(|s| s.name)
2206    }
2207
2208    pub(crate) fn last(&self) -> Symbol {
2209        self.last_opt().expect("segments were empty")
2210    }
2211
2212    pub(crate) fn whole_name(&self) -> String {
2213        self.segments
2214            .iter()
2215            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2216            .intersperse("::")
2217            .collect()
2218    }
2219
2220    /// Checks if this is a `T::Name` path for an associated type.
2221    pub(crate) fn is_assoc_ty(&self) -> bool {
2222        match self.res {
2223            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2224                if self.segments.len() != 1 =>
2225            {
2226                true
2227            }
2228            Res::Def(DefKind::AssocTy, _) => true,
2229            _ => false,
2230        }
2231    }
2232
2233    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2234        self.segments.last().map(|seg| &seg.args)
2235    }
2236
2237    pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
2238        self.segments.last().and_then(|seg| {
2239            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2240                Some(args.iter().filter_map(|arg| match arg {
2241                    GenericArg::Type(ty) => Some(ty),
2242                    _ => None,
2243                }))
2244            } else {
2245                None
2246            }
2247        })
2248    }
2249}
2250
2251#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2252pub(crate) enum GenericArg {
2253    Lifetime(Lifetime),
2254    Type(Type),
2255    Const(Box<ConstantKind>),
2256    Infer,
2257}
2258
2259impl GenericArg {
2260    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2261        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2262    }
2263
2264    pub(crate) fn as_ty(&self) -> Option<&Type> {
2265        if let Self::Type(ty) = self { Some(ty) } else { None }
2266    }
2267}
2268
2269#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2270pub(crate) enum GenericArgs {
2271    /// `<args, constraints = ..>`
2272    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2273    /// `(inputs) -> output`
2274    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2275    /// `(..)`
2276    ReturnTypeNotation,
2277}
2278
2279impl GenericArgs {
2280    pub(crate) fn is_empty(&self) -> bool {
2281        match self {
2282            GenericArgs::AngleBracketed { args, constraints } => {
2283                args.is_empty() && constraints.is_empty()
2284            }
2285            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2286            GenericArgs::ReturnTypeNotation => false,
2287        }
2288    }
2289    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2290        match self {
2291            GenericArgs::AngleBracketed { constraints, .. } => {
2292                Box::new(constraints.iter().cloned())
2293            }
2294            GenericArgs::Parenthesized { output, .. } => Box::new(
2295                output
2296                    .as_ref()
2297                    .map(|ty| AssocItemConstraint {
2298                        assoc: PathSegment {
2299                            name: sym::Output,
2300                            args: GenericArgs::AngleBracketed {
2301                                args: ThinVec::new(),
2302                                constraints: ThinVec::new(),
2303                            },
2304                        },
2305                        kind: AssocItemConstraintKind::Equality {
2306                            term: Term::Type((**ty).clone()),
2307                        },
2308                    })
2309                    .into_iter(),
2310            ),
2311            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2312        }
2313    }
2314}
2315
2316impl<'a> IntoIterator for &'a GenericArgs {
2317    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2318    type Item = GenericArg;
2319    fn into_iter(self) -> Self::IntoIter {
2320        match self {
2321            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2322            GenericArgs::Parenthesized { inputs, .. } => {
2323                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2324                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2325            }
2326            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2327        }
2328    }
2329}
2330
2331#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2332pub(crate) struct PathSegment {
2333    pub(crate) name: Symbol,
2334    pub(crate) args: GenericArgs,
2335}
2336
2337#[derive(Clone, Debug)]
2338pub(crate) enum TypeAliasInnerType {
2339    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2340    Union { fields: Vec<Item> },
2341    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2342}
2343
2344impl TypeAliasInnerType {
2345    fn has_stripped_entries(&self) -> Option<bool> {
2346        Some(match self {
2347            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2348            Self::Union { fields } | Self::Struct { fields, .. } => {
2349                fields.iter().any(|f| f.is_stripped())
2350            }
2351        })
2352    }
2353}
2354
2355#[derive(Clone, Debug)]
2356pub(crate) struct TypeAlias {
2357    pub(crate) type_: Type,
2358    pub(crate) generics: Generics,
2359    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2360    /// to be shown directly on the typedef page.
2361    pub(crate) inner_type: Option<TypeAliasInnerType>,
2362    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2363    /// alias instead of the final type. This will always have the final type, regardless of whether
2364    /// `type_` came from HIR or from metadata.
2365    ///
2366    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2367    /// final type).
2368    pub(crate) item_type: Option<Type>,
2369}
2370
2371#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2372pub(crate) struct BareFunctionDecl {
2373    pub(crate) safety: hir::Safety,
2374    pub(crate) generic_params: Vec<GenericParamDef>,
2375    pub(crate) decl: FnDecl,
2376    pub(crate) abi: ExternAbi,
2377}
2378
2379#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2380pub(crate) struct UnsafeBinderTy {
2381    pub(crate) generic_params: Vec<GenericParamDef>,
2382    pub(crate) ty: Type,
2383}
2384
2385#[derive(Clone, Debug)]
2386pub(crate) struct Static {
2387    pub(crate) type_: Box<Type>,
2388    pub(crate) mutability: Mutability,
2389    pub(crate) expr: Option<BodyId>,
2390}
2391
2392#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2393pub(crate) struct Constant {
2394    pub(crate) generics: Generics,
2395    pub(crate) kind: ConstantKind,
2396    pub(crate) type_: Type,
2397}
2398
2399#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2400pub(crate) enum Term {
2401    Type(Type),
2402    Constant(ConstantKind),
2403}
2404
2405impl Term {
2406    pub(crate) fn ty(&self) -> Option<&Type> {
2407        if let Term::Type(ty) = self { Some(ty) } else { None }
2408    }
2409}
2410
2411impl From<Type> for Term {
2412    fn from(ty: Type) -> Self {
2413        Term::Type(ty)
2414    }
2415}
2416
2417#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2418pub(crate) enum ConstantKind {
2419    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2420    /// `BodyId`, we need to handle it on its own.
2421    ///
2422    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2423    /// by a DefId. So this field must be different from `Extern`.
2424    TyConst { expr: Box<str> },
2425    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2426    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2427    Path { path: Box<str> },
2428    /// A constant (expression) that's not an item or associated item. These are usually found
2429    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2430    /// used to define explicit discriminant values for enum variants.
2431    Anonymous { body: BodyId },
2432    /// A constant from a different crate.
2433    Extern { def_id: DefId },
2434    /// `const FOO: u32 = ...;`
2435    Local { def_id: DefId, body: BodyId },
2436    /// An inferred constant as in `[10u8; _]`.
2437    Infer,
2438}
2439
2440impl ConstantKind {
2441    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2442        match *self {
2443            ConstantKind::TyConst { ref expr } => expr.to_string(),
2444            ConstantKind::Path { ref path } => path.to_string(),
2445            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2446            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2447                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2448            }
2449            ConstantKind::Infer => "_".to_string(),
2450        }
2451    }
2452
2453    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2454        match *self {
2455            ConstantKind::TyConst { .. }
2456            | ConstantKind::Path { .. }
2457            | ConstantKind::Anonymous { .. }
2458            | ConstantKind::Infer => None,
2459            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2460                print_evaluated_const(tcx, def_id, true, true)
2461            }
2462        }
2463    }
2464
2465    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2466        match *self {
2467            ConstantKind::TyConst { .. }
2468            | ConstantKind::Extern { .. }
2469            | ConstantKind::Path { .. }
2470            | ConstantKind::Infer => false,
2471            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2472                is_literal_expr(tcx, body.hir_id)
2473            }
2474        }
2475    }
2476}
2477
2478#[derive(Clone, Debug)]
2479pub(crate) struct Impl {
2480    pub(crate) safety: hir::Safety,
2481    pub(crate) generics: Generics,
2482    pub(crate) trait_: Option<Path>,
2483    pub(crate) for_: Type,
2484    pub(crate) items: Vec<Item>,
2485    pub(crate) polarity: ty::ImplPolarity,
2486    pub(crate) kind: ImplKind,
2487}
2488
2489impl Impl {
2490    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2491        self.trait_
2492            .as_ref()
2493            .map(|t| t.def_id())
2494            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2495            .unwrap_or_default()
2496    }
2497
2498    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2499        matches!(self.polarity, ty::ImplPolarity::Negative)
2500    }
2501}
2502
2503#[derive(Clone, Debug)]
2504pub(crate) enum ImplKind {
2505    Normal,
2506    Auto,
2507    FakeVariadic,
2508    Blanket(Box<Type>),
2509}
2510
2511impl ImplKind {
2512    pub(crate) fn is_auto(&self) -> bool {
2513        matches!(self, ImplKind::Auto)
2514    }
2515
2516    pub(crate) fn is_blanket(&self) -> bool {
2517        matches!(self, ImplKind::Blanket(_))
2518    }
2519
2520    pub(crate) fn is_fake_variadic(&self) -> bool {
2521        matches!(self, ImplKind::FakeVariadic)
2522    }
2523
2524    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2525        match self {
2526            ImplKind::Blanket(ty) => Some(ty),
2527            _ => None,
2528        }
2529    }
2530}
2531
2532#[derive(Clone, Debug)]
2533pub(crate) struct Import {
2534    pub(crate) kind: ImportKind,
2535    /// The item being re-exported.
2536    pub(crate) source: ImportSource,
2537    pub(crate) should_be_displayed: bool,
2538}
2539
2540impl Import {
2541    pub(crate) fn new_simple(
2542        name: Symbol,
2543        source: ImportSource,
2544        should_be_displayed: bool,
2545    ) -> Self {
2546        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2547    }
2548
2549    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2550        Self { kind: ImportKind::Glob, source, should_be_displayed }
2551    }
2552
2553    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2554        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2555    }
2556}
2557
2558#[derive(Clone, Debug)]
2559pub(crate) enum ImportKind {
2560    // use source as str;
2561    Simple(Symbol),
2562    // use source::*;
2563    Glob,
2564}
2565
2566#[derive(Clone, Debug)]
2567pub(crate) struct ImportSource {
2568    pub(crate) path: Path,
2569    pub(crate) did: Option<DefId>,
2570}
2571
2572#[derive(Clone, Debug)]
2573pub(crate) struct Macro {
2574    pub(crate) source: String,
2575    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2576    pub(crate) macro_rules: bool,
2577}
2578
2579#[derive(Clone, Debug)]
2580pub(crate) struct ProcMacro {
2581    pub(crate) kind: MacroKind,
2582    pub(crate) helpers: Vec<Symbol>,
2583}
2584
2585/// A constraint on an associated item.
2586///
2587/// ### Examples
2588///
2589/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2590/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2591/// * the `A: Bound` in `Trait<A: Bound>`
2592/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2593/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2594/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2595#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2596pub(crate) struct AssocItemConstraint {
2597    pub(crate) assoc: PathSegment,
2598    pub(crate) kind: AssocItemConstraintKind,
2599}
2600
2601/// The kind of [associated item constraint][AssocItemConstraint].
2602#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2603pub(crate) enum AssocItemConstraintKind {
2604    Equality { term: Term },
2605    Bound { bounds: Vec<GenericBound> },
2606}
2607
2608// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2609#[cfg(target_pointer_width = "64")]
2610mod size_asserts {
2611    use rustc_data_structures::static_assert_size;
2612
2613    use super::*;
2614    // tidy-alphabetical-start
2615    static_assert_size!(Crate, 16); // frequently moved by-value
2616    static_assert_size!(DocFragment, 32);
2617    static_assert_size!(GenericArg, 32);
2618    static_assert_size!(GenericArgs, 24);
2619    static_assert_size!(GenericParamDef, 40);
2620    static_assert_size!(Generics, 16);
2621    static_assert_size!(Item, 8);
2622    static_assert_size!(ItemInner, 144);
2623    static_assert_size!(ItemKind, 48);
2624    static_assert_size!(PathSegment, 32);
2625    static_assert_size!(Type, 32);
2626    // tidy-alphabetical-end
2627}