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