[go: up one dir, main page]

rustdoc/clean/
types.rs

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