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