1use std::fmt::Write;
2use std::hash::Hash;
3use std::path::PathBuf;
4use std::sync::{Arc, OnceLock as OnceCell};
5use std::{fmt, iter};
6
7use arrayvec::ArrayVec;
8use itertools::Either;
9use rustc_abi::{ExternAbi, VariantIdx};
10use rustc_ast as ast;
11use rustc_attr_ir::lang_items::LangItem;
12use rustc_attr_ir::{
13 AttributeKind, ConstStability, DeprecatedSince, Deprecation, DocAttribute, Stability,
14 StableSince, find_attr,
15};
16use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
17use rustc_data_structures::thin_vec::ThinVec;
18use rustc_hir as hir;
19use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
20use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
21use rustc_hir::{BodyId, Mutability};
22use rustc_index::IndexVec;
23use rustc_metadata::rendered_const;
24use rustc_middle::ty::fast_reject::SimplifiedType;
25use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
26use rustc_resolve::rustdoc::{
27 DocFragment, add_doc_fragment, attrs_to_doc_fragments, span_of_fragments,
28};
29use rustc_session::Session;
30use rustc_span::def_id::{CRATE_DEF_ID, ModId};
31use rustc_span::hygiene::MacroKind;
32use rustc_span::symbol::{Symbol, kw, sym};
33use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents, span_bug};
34use tracing::{debug, trace};
35
36pub(crate) use self::Type::{
37 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
38 RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
39};
40use crate::clean::cfg::Cfg;
41use crate::clean::clean_middle_path;
42use crate::clean::inline::{self, print_inlined_const};
43use crate::clean::utils::{is_literal_expr, print_evaluated_const};
44use crate::core::DocContext;
45use crate::formats::cache::Cache;
46use crate::formats::item_type::ItemType;
47use crate::html::format::HrefInfo;
48use crate::html::render::Context;
49use crate::passes::collect_intra_doc_links::UrlFragment;
50
51#[cfg(test)]
52mod tests;
53
54pub(crate) type ItemIdSet = FxHashSet<ItemId>;
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
57pub(crate) enum ItemId {
58 DefId(DefId),
60 Auto { trait_: DefId, for_: DefId },
62 Blanket { impl_id: DefId, for_: DefId },
64}
65
66#[derive(Debug, Copy, Clone, PartialEq, Eq)]
67pub(crate) enum Defaultness {
68 Implicit,
69 Default,
70 Final,
71}
72
73impl Defaultness {
74 pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
75 match defaultness {
76 hir::Defaultness::Default { .. } => Self::Implicit,
77 hir::Defaultness::Final => Self::Final,
78 }
79 }
80
81 pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
82 match defaultness {
83 hir::Defaultness::Default { .. } => Self::Default,
84 hir::Defaultness::Final => Self::Implicit,
85 }
86 }
87}
88
89impl ItemId {
90 #[inline]
91 pub(crate) fn is_local(self) -> bool {
92 match self {
93 ItemId::Auto { for_: id, .. }
94 | ItemId::Blanket { for_: id, .. }
95 | ItemId::DefId(id) => id.is_local(),
96 }
97 }
98
99 #[inline]
100 #[track_caller]
101 pub(crate) fn expect_def_id(self) -> DefId {
102 self.as_def_id()
103 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
104 }
105
106 #[inline]
107 pub(crate) fn as_def_id(self) -> Option<DefId> {
108 match self {
109 ItemId::DefId(id) => Some(id),
110 _ => None,
111 }
112 }
113
114 #[inline]
115 pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
116 self.as_def_id().and_then(|id| id.as_local())
117 }
118
119 #[inline]
120 pub(crate) fn krate(self) -> CrateNum {
121 match self {
122 ItemId::Auto { for_: id, .. }
123 | ItemId::Blanket { for_: id, .. }
124 | ItemId::DefId(id) => id.krate,
125 }
126 }
127}
128
129impl From<DefId> for ItemId {
130 fn from(id: DefId) -> Self {
131 Self::DefId(id)
132 }
133}
134
135#[derive(Debug)]
137pub(crate) struct Crate {
138 pub(crate) module: Item,
139 pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
141}
142
143impl Crate {
144 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
145 ExternalCrate::LOCAL.name(tcx)
146 }
147
148 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
149 ExternalCrate::LOCAL.src(tcx)
150 }
151}
152
153#[derive(Copy, Clone, Debug)]
154pub(crate) struct ExternalCrate {
155 pub(crate) crate_num: CrateNum,
156}
157
158impl ExternalCrate {
159 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
160
161 #[inline]
162 pub(crate) fn def_id(&self) -> DefId {
163 self.crate_num.as_def_id()
164 }
165
166 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
167 let krate_span = tcx.def_span(self.def_id());
168 tcx.sess.source_map().span_to_filename(krate_span)
169 }
170
171 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
172 tcx.crate_name(self.crate_num)
173 }
174
175 pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
176 match self.src(tcx) {
177 FileName::Real(ref p) => {
178 match p
179 .local_path()
180 .or(Some(p.path(RemapPathScopeComponents::DOCUMENTATION)))
181 .unwrap()
182 .parent()
183 {
184 Some(p) => p.to_path_buf(),
185 None => PathBuf::new(),
186 }
187 }
188 _ => PathBuf::new(),
189 }
190 }
191
192 pub(crate) fn location(
195 &self,
196 extern_url: Option<&str>,
197 extern_url_takes_precedence: bool,
198 dst: &std::path::Path,
199 tcx: TyCtxt<'_>,
200 ) -> ExternalLocation {
201 use ExternalLocation::*;
202
203 fn to_remote(url: impl ToString) -> ExternalLocation {
204 let mut url = url.to_string();
205 if !url.ends_with('/') {
206 url.push('/');
207 }
208 let is_absolute = url.starts_with('/')
209 || url.split_once(':').is_some_and(|(scheme, _)| {
210 scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic())
211 && scheme
212 .bytes()
213 .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'))
214 });
215 Remote { url, is_absolute }
216 }
217
218 let local_location = dst.join(self.name(tcx).as_str());
222 if local_location.is_dir() {
223 return Local;
224 }
225
226 if extern_url_takes_precedence && let Some(url) = extern_url {
227 return to_remote(url);
228 }
229
230 let did = self.crate_num.as_def_id();
233 find_attr!(tcx, did, Doc(d) =>d.html_root_url.map(|(url, _)| url))
234 .flatten()
235 .map(to_remote)
236 .or_else(|| extern_url.map(to_remote)) .unwrap_or(Unknown) }
239
240 fn fake_doc_items<T>(
241 &self,
242 tcx: TyCtxt<'_>,
243 f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>,
244 ) -> impl Iterator<Item = (DefId, T)> {
245 tcx.fake_doc_items(self.crate_num).into_iter().filter_map(move |did| f(*did, tcx))
246 }
247
248 pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = (DefId, Symbol)> {
249 self.retrieve_keywords_or_documented_attributes(tcx, |d| d.keyword.map(|(v, _)| v))
250 }
251 pub(crate) fn documented_attributes(
252 &self,
253 tcx: TyCtxt<'_>,
254 ) -> impl Iterator<Item = (DefId, Symbol)> {
255 self.retrieve_keywords_or_documented_attributes(tcx, |d| d.attribute.map(|(v, _)| v))
256 }
257
258 fn retrieve_keywords_or_documented_attributes<F: Fn(&DocAttribute) -> Option<Symbol>>(
259 &self,
260 tcx: TyCtxt<'_>,
261 callback: F,
262 ) -> impl Iterator<Item = (DefId, Symbol)> {
263 let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> {
264 find_attr!(tcx, did, Doc(d) => callback(d)).flatten().map(|value| (did, value))
265 };
266 self.fake_doc_items(tcx, as_target)
267 }
268
269 pub(crate) fn primitives(
270 &self,
271 tcx: TyCtxt<'_>,
272 ) -> impl Iterator<Item = (DefId, PrimitiveType)> {
273 fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
291 let (attr_span, prim_sym) = find_attr!(
292 tcx, def_id,
293 RustcDocPrimitive(span, prim) => (*span, *prim)
294 )?;
295 let Some(prim) = PrimitiveType::from_symbol(prim_sym) else {
296 span_bug!(attr_span, "primitive `{prim_sym}` is not a member of `PrimitiveType`");
297 };
298 Some((def_id, prim))
299 }
300
301 self.fake_doc_items(tcx, as_primitive)
302 }
303}
304
305#[derive(Debug)]
307pub(crate) enum ExternalLocation {
308 Remote { url: String, is_absolute: bool },
310 Local,
312 Unknown,
314}
315
316#[derive(Clone)]
320pub(crate) struct Item {
321 pub(crate) inner: Box<ItemInner>,
322}
323
324#[derive(Clone)]
330pub(crate) struct ItemInner {
331 pub(crate) name: Option<Symbol>,
334 pub(crate) kind: ItemKind,
337 pub(crate) attrs: Attributes,
338 pub(crate) stability: Option<Stability>,
340 pub(crate) item_id: ItemId,
341 pub(crate) inline_stmt_id: Option<LocalDefId>,
345 pub(crate) cfg: Option<Arc<Cfg>>,
346}
347
348impl std::ops::Deref for Item {
349 type Target = ItemInner;
350 fn deref(&self) -> &ItemInner {
351 &self.inner
352 }
353}
354
355impl fmt::Debug for Item {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 let alternate = f.alternate();
360 let mut fmt = f.debug_struct("Item");
362 fmt.field("name", &self.name).field("item_id", &self.item_id);
363 if alternate {
365 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
366 } else {
367 fmt.field("kind", &self.type_());
368 fmt.field("docs", &self.doc_value());
369 }
370 fmt.finish()
371 }
372}
373
374pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
375 Span::new(def_id.as_local().map_or_else(
376 || tcx.def_span(def_id),
377 |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
378 ))
379}
380
381fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
382 let parent = tcx.parent(def_id);
383 match tcx.def_kind(parent) {
384 DefKind::Struct | DefKind::Union => false,
385 DefKind::Variant => true,
386 parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
387 }
388}
389
390impl Item {
391 pub(crate) fn cfg_parent_ids_for_detached_item(&self, tcx: TyCtxt<'_>) -> Vec<LocalDefId> {
392 let Some(def_id) = self.inline_stmt_id.or(self.item_id.as_local_def_id()) else {
393 return Vec::new();
394 };
395 let mut ids = Vec::new();
396 let mut next = def_id;
397 while let Some(parent) = tcx.opt_local_parent(next) {
398 if parent == CRATE_DEF_ID {
399 break;
400 }
401 ids.push(parent);
402 next = parent;
403 }
404 ids.reverse();
405 ids
406 }
407
408 pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
412 let stability = self.inner.stability;
413 debug_assert!(
414 stability.is_some()
415 || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
416 "missing stability for cleaned item: {self:?}",
417 );
418 stability
419 }
420
421 pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
422 self.def_id().and_then(|did| tcx.lookup_const_stability(did))
423 }
424
425 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
426 self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
427 let stab = self.stability(tcx)?;
431 if let rustc_attr_ir::StabilityLevel::Stable {
432 allowed_through_unstable_modules: Some((note, _)),
433 ..
434 } = stab.level
435 {
436 Some(Deprecation {
437 since: DeprecatedSince::Unspecified,
438 note: Some(Ident { name: note, span: DUMMY_SP }),
439 suggestion: None,
440 })
441 } else {
442 None
443 }
444 })
445 }
446
447 pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
448 self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect())
449 }
450
451 pub(crate) fn is_unstable(&self) -> bool {
452 self.stability.is_some_and(|x| x.is_unstable())
453 }
454
455 pub(crate) fn is_exported_decl_macro(&self) -> bool {
456 match self.kind {
457 ItemKind::DeclMacro(..) => find_attr!(&self.attrs.other_attrs, MacroExport { .. }),
458 _ => false,
459 }
460 }
461
462 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
463 use rustc_ast::attr::AttributeExt;
464
465 self.item_id
466 .as_def_id()
467 .map(|did| {
468 #[allow(deprecated)]
469 tcx.get_all_attrs(did).iter().any(|attr| {
470 attr.doc_resolution_scope().is_some_and(|style| style == ast::AttrStyle::Inner)
471 })
472 })
473 .unwrap_or(false)
474 }
475
476 pub(crate) fn has_self_param(&self) -> bool {
478 matches!(&self.inner.kind, ItemKind::AssocFunction(f) if f.decl.receiver_type().is_some())
479 }
480
481 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
482 match self.kind.unstripped() {
483 ItemKind::Module(Module { span, .. }) => Some(*span),
484 ItemKind::Impl(Impl { kind: ImplKind::Auto, .. }) => None,
485 ItemKind::Impl(Impl { kind: ImplKind::Blanket(_), .. }) => {
486 if let ItemId::Blanket { impl_id, .. } = self.item_id {
487 Some(rustc_span(impl_id, tcx))
488 } else {
489 panic!("blanket impl item has non-blanket ID")
490 }
491 }
492 _ => self.def_id().map(|did| rustc_span(did, tcx)),
493 }
494 }
495
496 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
497 let deprecation_notes = find_attr!(&self.attrs.other_attrs, Deprecated { deprecation, .. } => deprecation.note.map(|note| note.span)).flatten();
498
499 span_of_fragments(&self.attrs.doc_strings)
500 .into_iter()
501 .chain(deprecation_notes)
502 .reduce(|a, b| a.to(b))
503 .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
504 }
505
506 pub(crate) fn doc_value(&self) -> String {
508 self.attrs.doc_value()
509 }
510
511 pub(crate) fn opt_doc_value(&self) -> Option<String> {
515 self.attrs.opt_doc_value()
516 }
517
518 pub(crate) fn from_def_id_and_parts(
519 def_id: DefId,
520 name: Option<Symbol>,
521 kind: ItemKind,
522 tcx: TyCtxt<'_>,
523 ) -> Item {
524 #[allow(deprecated)]
525 let hir_attrs = tcx.get_all_attrs(def_id);
526
527 Self::from_def_id_and_attrs_and_parts(
528 def_id,
529 name,
530 kind,
531 Attributes::from_hir(hir_attrs),
532 None,
533 )
534 }
535
536 pub(crate) fn from_def_id_and_attrs_and_parts(
537 def_id: DefId,
538 name: Option<Symbol>,
539 kind: ItemKind,
540 attrs: Attributes,
541 cfg: Option<Arc<Cfg>>,
542 ) -> Item {
543 trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
544
545 Item {
546 inner: Box::new(ItemInner {
547 item_id: def_id.into(),
548 kind,
549 attrs,
550 stability: None,
551 name,
552 cfg,
553 inline_stmt_id: None,
554 }),
555 }
556 }
557
558 pub(crate) fn item_or_reexport_id(&self) -> ItemId {
564 self.attrs
566 .doc_strings
567 .first()
568 .map(|x| x.item_id)
569 .flatten()
570 .map(ItemId::from)
571 .unwrap_or(self.item_id)
572 }
573
574 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
575 use crate::html::format::{href_with_path_check, link_tooltip};
576
577 let Some(links) = cx.cache().intra_doc_links.get(&self.item_or_reexport_id()) else {
578 return vec![];
579 };
580 links
581 .iter()
582 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
583 debug!(?id);
584 if let Ok(HrefInfo { mut url, .. }) = href_with_path_check(*id, cx, link_text) {
585 debug!(?url);
586 match fragment {
587 Some(UrlFragment::Item(def_id)) => {
588 write!(url, "{}", crate::html::format::fragment(*def_id, cx.tcx()))
589 .unwrap();
590 }
591 Some(UrlFragment::UserWritten(raw)) => {
592 url.push('#');
593 url.push_str(raw);
594 }
595 None => {}
596 }
597 Some(RenderedLink {
598 original_text: s.clone(),
599 new_text: link_text.clone(),
600 tooltip: link_tooltip(*id, fragment, cx, Some(link_text)).to_string(),
601 href: url,
602 })
603 } else {
604 None
605 }
606 })
607 .collect()
608 }
609
610 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
616 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
617 return vec![];
618 };
619 links
620 .iter()
621 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
622 original_text: s.clone(),
623 new_text: link_text.clone(),
624 href: String::new(),
625 tooltip: String::new(),
626 })
627 .collect()
628 }
629
630 pub(crate) fn is_crate(&self) -> bool {
631 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
632 }
633 pub(crate) fn is_mod(&self) -> bool {
634 self.type_() == ItemType::Module
635 }
636 pub(crate) fn is_struct(&self) -> bool {
637 self.type_() == ItemType::Struct
638 }
639 pub(crate) fn is_enum(&self) -> bool {
640 self.type_() == ItemType::Enum
641 }
642 pub(crate) fn is_variant(&self) -> bool {
643 self.type_() == ItemType::Variant
644 }
645 pub(crate) fn is_assoc_ty_with_body(&self) -> bool {
646 matches!(self.kind.unstripped(), ItemKind::AssocType(AssocType { type_: Some(_), .. }))
647 }
648 pub(crate) fn is_assoc_ty_without_body(&self) -> bool {
649 matches!(self.kind.unstripped(), ItemKind::AssocType(AssocType { type_: None, .. }))
650 }
651 pub(crate) fn is_assoc_const_with_body(&self) -> bool {
652 matches!(
653 self.kind.unstripped(),
654 ItemKind::AssocConstant(AssocConstant { body: Some(_), .. })
655 )
656 }
657 pub(crate) fn is_assoc_const_without_body(&self) -> bool {
658 matches!(self.kind.unstripped(), ItemKind::AssocConstant(AssocConstant { body: None, .. }))
659 }
660 pub(crate) fn is_assoc_fn_with_body(&self) -> bool {
661 self.type_() == ItemType::AssocFnWithBody
662 }
663 pub(crate) fn is_assoc_fn_without_body(&self) -> bool {
664 self.type_() == ItemType::AssocFnWithoutBody
665 }
666 pub(crate) fn is_primitive(&self) -> bool {
667 self.type_() == ItemType::Primitive
668 }
669 pub(crate) fn is_union(&self) -> bool {
670 self.type_() == ItemType::Union
671 }
672 pub(crate) fn is_import(&self) -> bool {
673 self.type_() == ItemType::Import
674 }
675 pub(crate) fn is_extern_crate(&self) -> bool {
676 self.type_() == ItemType::ExternCrate
677 }
678 pub(crate) fn is_keyword(&self) -> bool {
679 self.type_() == ItemType::Keyword
680 }
681 pub(crate) fn is_attribute(&self) -> bool {
682 self.type_() == ItemType::Attribute
683 }
684 pub(crate) fn is_fake_item(&self) -> bool {
693 matches!(self.type_(), ItemType::Primitive | ItemType::Keyword | ItemType::Attribute)
694 }
695 pub(crate) fn is_stripped(&self) -> bool {
696 match self.kind {
697 ItemKind::Stripped(..) => true,
698 ItemKind::Import(ref i) => !i.should_be_displayed,
699 _ => false,
700 }
701 }
702 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
703 match self.kind {
704 ItemKind::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
705 ItemKind::Union(ref union_) => Some(union_.has_stripped_entries()),
706 ItemKind::Enum(ref enum_) => Some(enum_.has_stripped_entries()),
707 ItemKind::Variant(ref v) => v.has_stripped_entries(),
708 ItemKind::TypeAlias(ref type_alias) => {
709 type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
710 }
711 _ => None,
712 }
713 }
714
715 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
716 self.stability(tcx).as_ref().and_then(|s| {
717 let mut classes = Vec::with_capacity(2);
718
719 if s.is_unstable() {
720 classes.push("unstable");
721 }
722
723 if self.deprecation(tcx).is_some() {
725 classes.push("deprecated");
726 }
727
728 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
729 })
730 }
731
732 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
733 self.stability(tcx).and_then(|stability| stability.stable_since())
734 }
735
736 pub(crate) fn is_non_exhaustive(&self) -> bool {
737 find_attr!(&self.attrs.other_attrs, NonExhaustive(..))
738 }
739
740 pub(crate) fn type_(&self) -> ItemType {
744 ItemType::from(self)
745 }
746
747 pub(crate) fn types(&self) -> impl Iterator<Item = ItemType> {
750 if let ItemKind::DeclMacro(_, macro_kinds) = self.kind {
751 Either::Right(macro_kinds.iter().map(|kind| match kind {
752 MacroKinds::ATTR => ItemType::DeclMacroAttribute,
753 MacroKinds::DERIVE => ItemType::DeclMacroDerive,
754 MacroKinds::BANG => ItemType::Macro,
755 _ => panic!("unsupported macro kind {kind:?}"),
756 }))
757 } else {
758 Either::Left(std::iter::once(self.type_()))
759 }
760 }
761
762 pub(crate) fn is_decl_macro(&self) -> bool {
765 matches!(self.kind, ItemKind::DeclMacro(..))
766 }
767
768 pub(crate) fn html_filename(&self) -> String {
770 format!("{type_}.{name}.html", type_ = self.type_(), name = self.name.unwrap())
771 }
772
773 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
775 fn build_fn_header(
776 def_id: DefId,
777 tcx: TyCtxt<'_>,
778 asyncness: ty::Asyncness,
779 ) -> hir::FnHeader {
780 let sig = tcx.fn_sig(def_id).skip_binder();
781 let constness = if tcx.is_const_fn(def_id) {
782 if let Some(assoc) = tcx.opt_associated_item(def_id)
786 && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) =
787 assoc.container
788 {
789 hir::Constness::NotConst
790 } else {
791 hir::Constness::Const { always: false }
792 }
793 } else {
794 hir::Constness::NotConst
795 };
796 let asyncness = match asyncness {
797 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
798 ty::Asyncness::No => hir::IsAsync::NotAsync,
799 };
800 hir::FnHeader {
801 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
802 hir::HeaderSafety::SafeTargetFeatures
803 } else {
804 sig.safety().into()
805 },
806 abi: sig.abi(),
807 constness,
808 asyncness,
809 }
810 }
811 let header = match self.kind {
812 ItemKind::ForeignFunction(_, safety) => {
813 let def_id = self.def_id().unwrap();
814 let abi = tcx.fn_sig(def_id).skip_binder().abi();
815 hir::FnHeader {
816 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
817 hir::HeaderSafety::SafeTargetFeatures
818 } else {
819 safety.into()
820 },
821 abi,
822 constness: hir::Constness::NotConst,
824 asyncness: hir::IsAsync::NotAsync,
825 }
826 }
827 ItemKind::Function(_) | ItemKind::AssocFunction(..) => {
828 let def_id = self.def_id().unwrap();
829 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
830 }
831 _ => return None,
832 };
833 Some(header)
834 }
835
836 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<ModId>> {
839 let def_id = match self.item_id {
840 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
842 ItemId::DefId(def_id) => def_id,
843 };
844
845 match self.kind {
846 ItemKind::Keyword | ItemKind::PrimitiveType(_) | ItemKind::Attribute => {
850 return Some(Visibility::Public);
851 }
852 ItemKind::StructField(..) if is_field_vis_inherited(tcx, def_id) => {
854 return None;
855 }
856 ItemKind::Variant(..) | ItemKind::Impl(..) => return None,
858 ItemKind::AssocConstant(..) | ItemKind::AssocType(..) | ItemKind::AssocFunction(..) => {
860 match tcx.associated_item(def_id).container {
861 ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
864 return None;
865 }
866 ty::AssocContainer::InherentImpl => {}
867 }
868 }
869 _ => {}
870 }
871 let def_id = match self.inline_stmt_id {
872 Some(inlined) => inlined.to_def_id(),
873 None => def_id,
874 };
875 Some(tcx.visibility(def_id))
876 }
877
878 pub fn is_doc_hidden(&self) -> bool {
879 self.attrs.is_doc_hidden()
880 }
881
882 pub fn def_id(&self) -> Option<DefId> {
883 self.item_id.as_def_id()
884 }
885}
886
887#[derive(Clone, Debug)]
888pub(crate) enum ItemKind {
889 ExternCrate {
890 src: Option<Symbol>,
892 },
893 Import(Import),
894 Struct(Struct),
895 Union(Union),
896 Enum(Enum),
897 Function(Box<Function>),
898 Module(Module),
899 TypeAlias(Box<TypeAlias>),
900 Static(Static),
901 Trait(Box<Trait>),
902 TraitAlias(TraitAlias),
903 Impl(Box<Impl>),
904 PlaceholderImpl,
907 AssocFunction(Box<AssocFunction>),
908 StructField(Type),
909 Variant(Variant),
910 ForeignFunction(Box<Function>, hir::Safety),
912 ForeignStatic(Static, hir::Safety),
914 ForeignType,
916 DeclMacro(DeclMacro, MacroKinds),
923 ProcMacro(ProcMacro),
924 PrimitiveType(PrimitiveType),
925 Constant(Box<Constant>),
926 AssocConstant(Box<AssocConstant>),
927 AssocType(Box<AssocType>),
928 Stripped(Box<ItemKind>),
930 Keyword,
933 Attribute,
936}
937
938impl ItemKind {
939 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
942 match self {
943 Self::Struct(s) => s.fields.iter(),
944 Self::Union(u) => u.fields.iter(),
945 Self::Variant(v) => match &v.kind {
946 VariantKind::CLike => [].iter(),
947 VariantKind::Tuple(t) => t.iter(),
948 VariantKind::Struct(s) => s.fields.iter(),
949 },
950 Self::Enum(e) => e.variants.iter(),
951 Self::Trait(t) => t.items.iter(),
952 Self::Impl(i) => i.items.iter(),
953 Self::Module(m) => m.items.iter(),
954 Self::ExternCrate { .. }
955 | Self::Import(_)
956 | Self::Function(_)
957 | Self::TypeAlias(_)
958 | Self::Static(_)
959 | Self::Constant(_)
960 | Self::TraitAlias(_)
961 | Self::AssocFunction(..)
962 | Self::StructField(_)
963 | Self::ForeignFunction(_, _)
964 | Self::ForeignStatic(_, _)
965 | Self::ForeignType
966 | Self::DeclMacro(..)
967 | Self::ProcMacro(_)
968 | Self::PrimitiveType(_)
969 | Self::AssocConstant(..)
970 | Self::AssocType(..)
971 | Self::Stripped(_)
972 | Self::Keyword
973 | Self::Attribute
974 | Self::PlaceholderImpl => [].iter(),
975 }
976 }
977
978 pub(crate) fn unstripped(&self) -> &Self {
979 match self {
980 Self::Stripped(kind) => kind,
981 _ => self,
982 }
983 }
984}
985
986#[derive(Clone, Debug)]
987pub(crate) struct Module {
988 pub(crate) items: Vec<Item>,
989 pub(crate) span: Span,
990}
991
992#[derive(Clone, Debug, PartialEq, Eq, Hash)]
996pub(crate) struct ItemLink {
997 pub(crate) link: Box<str>,
999 pub(crate) link_text: Box<str>,
1004 pub(crate) page_id: DefId,
1008 pub(crate) fragment: Option<UrlFragment>,
1010}
1011
1012pub struct RenderedLink {
1013 pub(crate) original_text: Box<str>,
1017 pub(crate) new_text: Box<str>,
1019 pub(crate) href: String,
1021 pub(crate) tooltip: String,
1023}
1024
1025#[derive(Clone, Debug, Default)]
1028pub(crate) struct Attributes {
1029 pub(crate) doc_strings: Vec<DocFragment>,
1030 pub(crate) other_attrs: ThinVec<rustc_attr_ir::Attribute>,
1031}
1032
1033impl Attributes {
1034 pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool {
1035 find_attr!(&self.other_attrs, Doc(d) if callback(d))
1036 }
1037
1038 pub(crate) fn is_doc_hidden(&self) -> bool {
1039 find_attr!(&self.other_attrs, Doc(d) if d.hidden.is_some())
1040 }
1041
1042 pub(crate) fn from_hir(attrs: &[rustc_attr_ir::Attribute]) -> Attributes {
1043 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1044 }
1045
1046 pub(crate) fn from_hir_with_additional(
1047 attrs: &[rustc_attr_ir::Attribute],
1048 (additional_attrs, def_id): (&[rustc_attr_ir::Attribute], DefId),
1049 ) -> Attributes {
1050 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1052 let attrs2 = attrs.iter().map(|attr| (attr, None));
1053 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1054 }
1055
1056 pub(crate) fn from_hir_iter<'a>(
1057 attrs: impl Iterator<Item = (&'a rustc_attr_ir::Attribute, Option<DefId>)>,
1058 doc_only: bool,
1059 ) -> Attributes {
1060 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1061 Attributes { doc_strings, other_attrs }
1062 }
1063
1064 pub(crate) fn doc_value(&self) -> String {
1066 self.opt_doc_value().unwrap_or_default()
1067 }
1068
1069 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1073 (!self.doc_strings.is_empty()).then(|| {
1074 let mut res = String::new();
1075 for frag in &self.doc_strings {
1076 add_doc_fragment(&mut res, frag);
1077 }
1078 res.pop();
1079 res
1080 })
1081 }
1082
1083 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1084 let mut aliases = FxIndexSet::default();
1085
1086 for attr in &self.other_attrs {
1087 if let rustc_attr_ir::Attribute::Parsed(AttributeKind::Doc(d)) = attr {
1088 for (alias, _) in &d.aliases {
1089 aliases.insert(*alias);
1090 }
1091 }
1092 }
1093 aliases.into_iter().collect::<Vec<_>>().into()
1094 }
1095
1096 pub(crate) fn merge_with(&mut self, other: Self) {
1097 let Self { doc_strings, other_attrs } = other;
1098 self.doc_strings.extend(doc_strings);
1099 self.other_attrs.extend(other_attrs);
1100 }
1101}
1102
1103#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1104pub(crate) enum GenericBound {
1105 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1106 Outlives(Lifetime),
1107 Use(Vec<PreciseCapturingArg>),
1109}
1110
1111impl GenericBound {
1112 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1113 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1114 }
1115
1116 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1117 Self::sized_with(
1118 cx,
1119 hir::TraitBoundModifiers {
1120 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1121 constness: hir::BoundConstness::Never,
1122 },
1123 )
1124 }
1125
1126 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1127 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1128 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1129 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1130 inline::record_extern_fqn(cx, did, ItemType::Trait);
1131 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1132 }
1133
1134 pub(crate) fn is_trait_bound(&self) -> bool {
1135 matches!(self, Self::TraitBound(..))
1136 }
1137
1138 pub(crate) fn is_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1139 self.is_bounded_by_lang_item(tcx, LangItem::Sized)
1140 }
1141
1142 pub(crate) fn is_meta_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1143 self.is_bounded_by_lang_item(tcx, LangItem::MetaSized)
1144 }
1145
1146 fn is_bounded_by_lang_item(&self, tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
1147 if let GenericBound::TraitBound(poly_trait_ref, rustc_hir::TraitBoundModifiers::NONE) = self
1148 && tcx.is_lang_item(poly_trait_ref.trait_.def_id(), lang_item)
1149 {
1150 return true;
1151 }
1152 false
1153 }
1154
1155 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1156 if let GenericBound::TraitBound(poly_trait_ref, _) = self {
1157 Some(poly_trait_ref.trait_.clone())
1158 } else {
1159 None
1160 }
1161 }
1162}
1163
1164#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1165pub(crate) struct Lifetime(pub Symbol);
1166
1167impl Lifetime {
1168 pub(crate) fn statik() -> Lifetime {
1169 Lifetime(kw::StaticLifetime)
1170 }
1171
1172 pub(crate) fn elided() -> Lifetime {
1173 Lifetime(kw::UnderscoreLifetime)
1174 }
1175}
1176
1177#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1178pub(crate) enum PreciseCapturingArg {
1179 Lifetime(Lifetime),
1180 Param(Symbol),
1181}
1182
1183impl PreciseCapturingArg {
1184 pub(crate) fn name(self) -> Symbol {
1185 match self {
1186 PreciseCapturingArg::Lifetime(lt) => lt.0,
1187 PreciseCapturingArg::Param(param) => param,
1188 }
1189 }
1190}
1191
1192#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1193pub(crate) enum WherePredicate {
1194 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1195 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1196 ProjectionPredicate { lhs: QPathData, rhs: Term },
1197}
1198
1199impl WherePredicate {
1200 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1201 match self {
1202 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1203 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1204 _ => None,
1205 }
1206 }
1207}
1208
1209#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1210pub(crate) enum GenericParamDefKind {
1211 Lifetime { outlives: ThinVec<Lifetime> },
1212 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1213 Const { ty: Box<Type>, default: Option<Box<String>> },
1215}
1216
1217impl GenericParamDefKind {
1218 pub(crate) fn is_type(&self) -> bool {
1219 matches!(self, GenericParamDefKind::Type { .. })
1220 }
1221}
1222
1223#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1224pub(crate) struct GenericParamDef {
1225 pub(crate) name: Symbol,
1226 pub(crate) def_id: DefId,
1227 pub(crate) kind: GenericParamDefKind,
1228}
1229
1230impl GenericParamDef {
1231 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1232 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1233 }
1234
1235 pub(crate) fn is_synthetic_param(&self) -> bool {
1236 match self.kind {
1237 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1238 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1239 }
1240 }
1241
1242 pub(crate) fn is_type(&self) -> bool {
1243 self.kind.is_type()
1244 }
1245
1246 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1247 match self.kind {
1248 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1249 _ => None,
1250 }
1251 }
1252}
1253
1254#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1256pub(crate) struct Generics {
1257 pub(crate) params: ThinVec<GenericParamDef>,
1258 pub(crate) where_predicates: ThinVec<WherePredicate>,
1259}
1260
1261impl Generics {
1262 pub(crate) fn is_empty(&self) -> bool {
1263 self.params.is_empty() && self.where_predicates.is_empty()
1264 }
1265}
1266
1267#[derive(Clone, Debug)]
1268pub(crate) struct Function {
1269 pub(crate) generics: Generics,
1270 pub(crate) decl: FnDecl,
1271}
1272
1273#[derive(Clone, Debug)]
1274pub(crate) struct AssocFunction {
1275 pub(crate) generics: Generics,
1276 pub(crate) decl: FnDecl,
1277 pub(crate) body: Option<Defaultness>,
1278}
1279
1280#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1281pub(crate) struct FnDecl {
1282 pub(crate) inputs: Vec<Parameter>,
1283 pub(crate) output: Type,
1284 pub(crate) c_variadic: bool,
1285}
1286
1287impl FnDecl {
1288 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1289 self.inputs.first().and_then(|v| v.to_receiver())
1290 }
1291}
1292
1293#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1295pub(crate) struct Parameter {
1296 pub(crate) name: Option<Symbol>,
1297 pub(crate) type_: Type,
1298 pub(crate) is_const: bool,
1301 pub(crate) is_splat: bool,
1304}
1305
1306impl Parameter {
1307 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1308 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1309 }
1310}
1311
1312#[derive(Clone, Debug)]
1313pub(crate) struct Trait {
1314 pub(crate) def_id: DefId,
1315 pub(crate) items: Vec<Item>,
1316 pub(crate) generics: Generics,
1317 pub(crate) bounds: Vec<GenericBound>,
1318}
1319
1320impl Trait {
1321 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1322 tcx.trait_is_auto(self.def_id)
1323 }
1324 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1325 tcx.doc_notable_trait(self.def_id).is_some()
1326 }
1327 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1328 tcx.trait_def(self.def_id).safety
1329 }
1330 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1331 tcx.is_dyn_compatible(self.def_id)
1332 }
1333 pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
1334 tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
1335 }
1336}
1337
1338#[derive(Clone, Debug)]
1339pub(crate) struct TraitAlias {
1340 pub(crate) generics: Generics,
1341 pub(crate) bounds: Vec<GenericBound>,
1342}
1343
1344#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1346pub(crate) struct PolyTrait {
1347 pub(crate) trait_: Path,
1348 pub(crate) generic_params: Vec<GenericParamDef>,
1349}
1350
1351#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1353pub(crate) enum Type {
1354 Path {
1359 path: Path,
1360 },
1361 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1363 Generic(Symbol),
1365 SelfTy,
1367 Primitive(PrimitiveType),
1369 BareFunction(Box<BareFunctionDecl>),
1371 Tuple(Vec<Type>),
1373 Slice(Box<Type>),
1375 Array(Box<Type>, Box<str>),
1379 Pat(Box<Type>, Box<str>),
1380 FieldOf(Box<Type>, Box<str>),
1381 RawPointer(Mutability, Box<Type>),
1383 BorrowedRef {
1385 lifetime: Option<Lifetime>,
1386 mutability: Mutability,
1387 type_: Box<Type>,
1388 },
1389
1390 QPath(Box<QPathData>),
1392
1393 Infer,
1395
1396 ImplTrait(Vec<GenericBound>),
1398
1399 UnsafeBinder(Box<UnsafeBinderTy>),
1400}
1401
1402impl Type {
1403 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1405 let mut result = self;
1406 while let Type::BorrowedRef { type_, .. } = result {
1407 result = type_;
1408 }
1409 result
1410 }
1411
1412 pub(crate) fn is_borrowed_ref(&self) -> bool {
1413 matches!(self, Type::BorrowedRef { .. })
1414 }
1415
1416 fn is_type_alias(&self) -> bool {
1417 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1418 }
1419
1420 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1441 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1444 (self.without_borrowed_ref(), other.without_borrowed_ref())
1445 } else {
1446 (self, other)
1447 };
1448
1449 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1455 return true;
1456 }
1457
1458 match (self_cleared, other_cleared) {
1459 (Type::Tuple(a), Type::Tuple(b)) => {
1461 a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
1462 }
1463 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1464 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1465 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1466 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1467 }
1468 (
1469 Type::BorrowedRef { mutability, type_, .. },
1470 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1471 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1472 (Type::Infer, _) | (_, Type::Infer) => true,
1474 (_, Type::Generic(_)) => true,
1477 (Type::Generic(_), _) => false,
1478 (Type::SelfTy, Type::SelfTy) => true,
1480 (Type::Path { path: a }, Type::Path { path: b }) => {
1482 a.def_id() == b.def_id()
1483 && a.generics()
1484 .zip(b.generics())
1485 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1486 .unwrap_or(true)
1487 }
1488 (a, b) => a
1490 .def_id(cache)
1491 .and_then(|a| Some((a, b.def_id(cache)?)))
1492 .map(|(a, b)| a == b)
1493 .unwrap_or(false),
1494 }
1495 }
1496
1497 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1498 match *self {
1499 Primitive(p) | BorrowedRef { type_: Primitive(p), .. } => Some(p),
1500 Slice(..) | BorrowedRef { type_: Slice(..), .. } => Some(PrimitiveType::Slice),
1501 Array(..) | BorrowedRef { type_: Array(..), .. } => Some(PrimitiveType::Array),
1502 Tuple(ref tys) => {
1503 if tys.is_empty() {
1504 Some(PrimitiveType::Unit)
1505 } else {
1506 Some(PrimitiveType::Tuple)
1507 }
1508 }
1509 RawPointer(..) => Some(PrimitiveType::RawPointer),
1510 BareFunction(..) => Some(PrimitiveType::Fn),
1511 _ => None,
1512 }
1513 }
1514
1515 pub(crate) fn sugared_async_return_type(self) -> Type {
1525 if let Type::ImplTrait(mut v) = self
1526 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1527 && let Some(segment) = trait_.segments.pop()
1528 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1529 && let Some(constraint) = constraints.pop()
1530 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1531 && let Term::Type(ty) = term
1532 {
1533 ty
1534 } else {
1535 panic!("unexpected async fn return type")
1536 }
1537 }
1538
1539 pub(crate) fn is_assoc_ty(&self) -> bool {
1541 match self {
1542 Type::Path { path, .. } => path.is_assoc_ty(),
1543 _ => false,
1544 }
1545 }
1546
1547 pub(crate) fn is_self_type(&self) -> bool {
1548 matches!(*self, Type::SelfTy)
1549 }
1550
1551 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1552 match self {
1553 Type::Path { path, .. } => path.generic_args(),
1554 _ => None,
1555 }
1556 }
1557
1558 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1559 match self {
1560 Type::Path { path, .. } => path.generics(),
1561 _ => None,
1562 }
1563 }
1564
1565 pub(crate) fn is_full_generic(&self) -> bool {
1566 matches!(self, Type::Generic(_))
1567 }
1568
1569 pub(crate) fn is_unit(&self) -> bool {
1570 matches!(self, Type::Tuple(v) if v.is_empty())
1571 }
1572
1573 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1577 let t: PrimitiveType = match self {
1578 Type::Path { path } => return Some(path.def_id()),
1579 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1580 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1581 BorrowedRef { type_: Generic(..), .. } => PrimitiveType::Reference,
1582 BorrowedRef { type_, .. } => return type_.def_id(cache),
1583 Tuple(tys) => {
1584 if tys.is_empty() {
1585 PrimitiveType::Unit
1586 } else {
1587 PrimitiveType::Tuple
1588 }
1589 }
1590 BareFunction(..) => PrimitiveType::Fn,
1591 Slice(..) => PrimitiveType::Slice,
1592 Array(..) => PrimitiveType::Array,
1593 Type::Pat(..) => PrimitiveType::Pat,
1594 Type::FieldOf(..) => PrimitiveType::FieldOf,
1595 RawPointer(..) => PrimitiveType::RawPointer,
1596 QPath(QPathData { self_type, .. }) => return self_type.def_id(cache),
1597 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1598 };
1599 Primitive(t).def_id(cache)
1600 }
1601}
1602
1603#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1604pub(crate) struct QPathData {
1605 pub assoc: PathSegment,
1606 pub self_type: Type,
1607 pub should_fully_qualify: bool,
1609 pub trait_: Option<Path>,
1610}
1611
1612#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1619pub(crate) enum PrimitiveType {
1620 Isize,
1621 I8,
1622 I16,
1623 I32,
1624 I64,
1625 I128,
1626 Usize,
1627 U8,
1628 U16,
1629 U32,
1630 U64,
1631 U128,
1632 F16,
1633 F32,
1634 F64,
1635 F128,
1636 Char,
1637 Bool,
1638 Str,
1639 Slice,
1640 Array,
1641 Pat,
1642 FieldOf,
1643 Tuple,
1644 Unit,
1645 RawPointer,
1646 Reference,
1647 Fn,
1648 Never,
1649}
1650
1651type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1652impl PrimitiveType {
1653 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1654 use ast::{FloatTy, IntTy, UintTy};
1655 match prim {
1656 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1657 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1658 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1659 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1660 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1661 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1662 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1663 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1664 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1665 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1666 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1667 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1668 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1669 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1670 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1671 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1672 hir::PrimTy::Str => PrimitiveType::Str,
1673 hir::PrimTy::Bool => PrimitiveType::Bool,
1674 hir::PrimTy::Char => PrimitiveType::Char,
1675 }
1676 }
1677
1678 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1679 match s {
1680 sym::isize => Some(PrimitiveType::Isize),
1681 sym::i8 => Some(PrimitiveType::I8),
1682 sym::i16 => Some(PrimitiveType::I16),
1683 sym::i32 => Some(PrimitiveType::I32),
1684 sym::i64 => Some(PrimitiveType::I64),
1685 sym::i128 => Some(PrimitiveType::I128),
1686 sym::usize => Some(PrimitiveType::Usize),
1687 sym::u8 => Some(PrimitiveType::U8),
1688 sym::u16 => Some(PrimitiveType::U16),
1689 sym::u32 => Some(PrimitiveType::U32),
1690 sym::u64 => Some(PrimitiveType::U64),
1691 sym::u128 => Some(PrimitiveType::U128),
1692 sym::bool => Some(PrimitiveType::Bool),
1693 sym::char => Some(PrimitiveType::Char),
1694 sym::str => Some(PrimitiveType::Str),
1695 sym::f16 => Some(PrimitiveType::F16),
1696 sym::f32 => Some(PrimitiveType::F32),
1697 sym::f64 => Some(PrimitiveType::F64),
1698 sym::f128 => Some(PrimitiveType::F128),
1699 sym::array => Some(PrimitiveType::Array),
1700 sym::slice => Some(PrimitiveType::Slice),
1701 sym::tuple => Some(PrimitiveType::Tuple),
1702 sym::unit => Some(PrimitiveType::Unit),
1703 sym::pointer => Some(PrimitiveType::RawPointer),
1704 sym::reference => Some(PrimitiveType::Reference),
1705 kw::Fn => Some(PrimitiveType::Fn),
1706 sym::never => Some(PrimitiveType::Never),
1707 _ => None,
1708 }
1709 }
1710
1711 pub(crate) fn from_ty(ty: Ty<'_>) -> Option<Self> {
1712 match ty.kind() {
1713 ty::Array(..) => Some(Self::Array),
1714 ty::Bool => Some(Self::Bool),
1715 ty::Char => Some(Self::Char),
1716 ty::FnDef(..) | ty::FnPtr(..) => Some(Self::Fn),
1717 ty::Int(int) => Some(Self::from(*int)),
1718 ty::Uint(uint) => Some(Self::from(*uint)),
1719 ty::Float(float) => Some(Self::from(*float)),
1720 ty::Never => Some(Self::Never),
1721 ty::Pat(..) => Some(Self::Pat),
1722 ty::RawPtr(..) => Some(Self::RawPointer),
1723 ty::Ref(..) => Some(Self::Reference),
1724 ty::Slice(..) => Some(Self::Slice),
1725 ty::Str => Some(Self::Str),
1726 ty::Tuple(elems) if elems.is_empty() => Some(Self::Unit),
1727 ty::Tuple(_) => Some(Self::Tuple),
1728 ty::Adt(..)
1729 | ty::Alias(_, ..)
1730 | ty::Bound(..)
1731 | ty::Closure(..)
1732 | ty::Coroutine(..)
1733 | ty::CoroutineClosure(..)
1734 | ty::CoroutineWitness(..)
1735 | ty::Dynamic(..)
1736 | ty::Error(..)
1737 | ty::Foreign(..)
1738 | ty::Infer(..)
1739 | ty::Param(..)
1740 | ty::Placeholder(..)
1741 | ty::UnsafeBinder(..) => None,
1742 }
1743 }
1744
1745 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1746 use PrimitiveType::*;
1747 use ty::{FloatTy, IntTy, UintTy};
1748 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1749
1750 let single = |x| iter::once(x).collect();
1751 CELL.get_or_init(move || {
1752 map! {
1753 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1754 I8 => single(SimplifiedType::Int(IntTy::I8)),
1755 I16 => single(SimplifiedType::Int(IntTy::I16)),
1756 I32 => single(SimplifiedType::Int(IntTy::I32)),
1757 I64 => single(SimplifiedType::Int(IntTy::I64)),
1758 I128 => single(SimplifiedType::Int(IntTy::I128)),
1759 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1760 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1761 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1762 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1763 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1764 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1765 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1766 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1767 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1768 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1769 Str => single(SimplifiedType::Str),
1770 Bool => single(SimplifiedType::Bool),
1771 Char => single(SimplifiedType::Char),
1772 Array => single(SimplifiedType::Array),
1773 Slice => single(SimplifiedType::Slice),
1774 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1780 Unit => single(SimplifiedType::Tuple(0)),
1781 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1782 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1783 Fn => single(SimplifiedType::Function(1)),
1786 Never => single(SimplifiedType::Never),
1787 }
1788 })
1789 }
1790
1791 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1792 Self::simplified_types()
1793 .get(self)
1794 .into_iter()
1795 .flatten()
1796 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1797 .copied()
1798 }
1799
1800 pub(crate) fn as_sym(&self) -> Symbol {
1801 use PrimitiveType::*;
1802 match self {
1803 Isize => sym::isize,
1804 I8 => sym::i8,
1805 I16 => sym::i16,
1806 I32 => sym::i32,
1807 I64 => sym::i64,
1808 I128 => sym::i128,
1809 Usize => sym::usize,
1810 U8 => sym::u8,
1811 U16 => sym::u16,
1812 U32 => sym::u32,
1813 U64 => sym::u64,
1814 U128 => sym::u128,
1815 F16 => sym::f16,
1816 F32 => sym::f32,
1817 F64 => sym::f64,
1818 F128 => sym::f128,
1819 Str => sym::str,
1820 Bool => sym::bool,
1821 Char => sym::char,
1822 Array => sym::array,
1823 Pat => sym::pat,
1824 FieldOf => kw::FieldOf,
1825 Slice => sym::slice,
1826 Tuple => sym::tuple,
1827 Unit => sym::unit,
1828 RawPointer => sym::pointer,
1829 Reference => sym::reference,
1830 Fn => kw::Fn,
1831 Never => sym::never,
1832 }
1833 }
1834
1835 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1847 fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<PrimitiveType> {
1848 let (attr_span, prim_sym) = find_attr!(
1849 tcx, def_id,
1850 RustcDocPrimitive(span, prim) => (*span, *prim)
1851 )?;
1852 let Some(prim) = PrimitiveType::from_symbol(prim_sym) else {
1853 span_bug!(attr_span, "primitive `{prim_sym}` is not a member of `PrimitiveType`");
1854 };
1855 Some(prim)
1856 }
1857
1858 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1859 PRIMITIVE_LOCATIONS.get_or_init(|| {
1860 let mut primitive_locations = FxIndexMap::default();
1861 let mut ids = tcx.all_fake_doc_items(()).clone();
1865
1866 ids.iter_mut().partition_in_place(|id| tcx.crate_name(id.krate) == sym::core);
1870 for def_id in ids {
1871 if let Some(prim) = as_primitive(def_id, tcx) {
1872 primitive_locations.insert(prim, def_id);
1873 }
1874 }
1875
1876 primitive_locations
1877 })
1878 }
1879}
1880
1881impl From<ty::IntTy> for PrimitiveType {
1882 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1883 match int_ty {
1884 ty::IntTy::Isize => PrimitiveType::Isize,
1885 ty::IntTy::I8 => PrimitiveType::I8,
1886 ty::IntTy::I16 => PrimitiveType::I16,
1887 ty::IntTy::I32 => PrimitiveType::I32,
1888 ty::IntTy::I64 => PrimitiveType::I64,
1889 ty::IntTy::I128 => PrimitiveType::I128,
1890 }
1891 }
1892}
1893
1894impl From<ty::UintTy> for PrimitiveType {
1895 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1896 match uint_ty {
1897 ty::UintTy::Usize => PrimitiveType::Usize,
1898 ty::UintTy::U8 => PrimitiveType::U8,
1899 ty::UintTy::U16 => PrimitiveType::U16,
1900 ty::UintTy::U32 => PrimitiveType::U32,
1901 ty::UintTy::U64 => PrimitiveType::U64,
1902 ty::UintTy::U128 => PrimitiveType::U128,
1903 }
1904 }
1905}
1906
1907impl From<ty::FloatTy> for PrimitiveType {
1908 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1909 match float_ty {
1910 ty::FloatTy::F16 => PrimitiveType::F16,
1911 ty::FloatTy::F32 => PrimitiveType::F32,
1912 ty::FloatTy::F64 => PrimitiveType::F64,
1913 ty::FloatTy::F128 => PrimitiveType::F128,
1914 }
1915 }
1916}
1917
1918impl From<hir::PrimTy> for PrimitiveType {
1919 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1920 match prim_ty {
1921 hir::PrimTy::Int(int_ty) => int_ty.into(),
1922 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1923 hir::PrimTy::Float(float_ty) => float_ty.into(),
1924 hir::PrimTy::Str => PrimitiveType::Str,
1925 hir::PrimTy::Bool => PrimitiveType::Bool,
1926 hir::PrimTy::Char => PrimitiveType::Char,
1927 }
1928 }
1929}
1930
1931#[derive(Clone, Debug)]
1932pub(crate) struct Struct {
1933 pub(crate) ctor_kind: Option<CtorKind>,
1934 pub(crate) generics: Generics,
1935 pub(crate) fields: ThinVec<Item>,
1936}
1937
1938impl Struct {
1939 pub(crate) fn has_stripped_entries(&self) -> bool {
1940 self.fields.iter().any(|f| f.is_stripped())
1941 }
1942}
1943
1944#[derive(Clone, Debug)]
1945pub(crate) struct Union {
1946 pub(crate) generics: Generics,
1947 pub(crate) fields: Vec<Item>,
1948}
1949
1950impl Union {
1951 pub(crate) fn has_stripped_entries(&self) -> bool {
1952 self.fields.iter().any(|f| f.is_stripped())
1953 }
1954}
1955
1956#[derive(Clone, Debug)]
1960pub(crate) struct VariantStruct {
1961 pub(crate) fields: ThinVec<Item>,
1962}
1963
1964impl VariantStruct {
1965 pub(crate) fn has_stripped_entries(&self) -> bool {
1966 self.fields.iter().any(|f| f.is_stripped())
1967 }
1968}
1969
1970#[derive(Clone, Debug)]
1971pub(crate) struct Enum {
1972 pub(crate) variants: IndexVec<VariantIdx, Item>,
1973 pub(crate) generics: Generics,
1974}
1975
1976impl Enum {
1977 pub(crate) fn has_stripped_entries(&self) -> bool {
1978 self.variants.iter().any(|f| f.is_stripped())
1979 }
1980
1981 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
1982 self.variants.iter().filter(|v| !v.is_stripped())
1983 }
1984}
1985
1986#[derive(Clone, Debug)]
1987pub(crate) struct Variant {
1988 pub kind: VariantKind,
1989 pub discriminant: Option<Discriminant>,
1990}
1991
1992#[derive(Clone, Debug)]
1993pub(crate) enum VariantKind {
1994 CLike,
1995 Tuple(ThinVec<Item>),
1996 Struct(VariantStruct),
1997}
1998
1999impl Variant {
2000 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2001 match &self.kind {
2002 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2003 VariantKind::CLike | VariantKind::Tuple(_) => None,
2004 }
2005 }
2006}
2007
2008#[derive(Clone, Debug)]
2009pub(crate) struct Discriminant {
2010 pub(super) expr: Option<BodyId>,
2013 pub(super) value: DefId,
2014}
2015
2016impl Discriminant {
2017 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2020 self.expr
2021 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2022 }
2023 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2024 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2025 }
2026}
2027
2028#[derive(Copy, Clone, Debug)]
2031pub(crate) struct Span(rustc_span::Span);
2032
2033impl Span {
2034 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2039 Self(sp.source_callsite())
2040 }
2041
2042 pub(crate) fn inner(&self) -> rustc_span::Span {
2043 self.0
2044 }
2045
2046 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2047 sess.source_map().span_to_filename(self.0)
2048 }
2049
2050 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2051 sess.source_map().lookup_char_pos(self.0.lo())
2052 }
2053
2054 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2055 sess.source_map().lookup_char_pos(self.0.hi())
2056 }
2057
2058 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2059 self.lo(sess).file.cnum
2061 }
2062}
2063
2064#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2065pub(crate) struct Path {
2066 pub(crate) res: Res,
2067 pub(crate) segments: ThinVec<PathSegment>,
2068}
2069
2070impl Path {
2071 pub(crate) fn def_id(&self) -> DefId {
2072 self.res.def_id()
2073 }
2074
2075 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2076 self.segments.last().map(|s| s.name)
2077 }
2078
2079 pub(crate) fn last(&self) -> Symbol {
2080 self.last_opt().expect("segments were empty")
2081 }
2082
2083 pub(crate) fn whole_name(&self) -> String {
2084 self.segments
2085 .iter()
2086 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2087 .intersperse("::")
2088 .collect()
2089 }
2090
2091 pub(crate) fn is_assoc_ty(&self) -> bool {
2093 match self.res {
2094 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2095 if self.segments.len() != 1 =>
2096 {
2097 true
2098 }
2099 Res::Def(DefKind::AssocTy, _) => true,
2100 _ => false,
2101 }
2102 }
2103
2104 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2105 self.segments.last().map(|seg| &seg.args)
2106 }
2107
2108 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2109 self.segments.last().and_then(|seg| {
2110 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2111 Some(args.iter().filter_map(|arg| match arg {
2112 GenericArg::Type(ty) => Some(ty),
2113 _ => None,
2114 }))
2115 } else {
2116 None
2117 }
2118 })
2119 }
2120}
2121
2122#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2123pub(crate) enum GenericArg {
2124 Lifetime(Lifetime),
2125 Type(Type),
2126 Const(Box<ConstantExpr>),
2127 Infer,
2128}
2129
2130impl GenericArg {
2131 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2132 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2133 }
2134
2135 pub(crate) fn as_ty(&self) -> Option<&Type> {
2136 if let Self::Type(ty) = self { Some(ty) } else { None }
2137 }
2138}
2139
2140#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2141pub(crate) enum GenericArgs {
2142 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2144 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2146 ReturnTypeNotation,
2148}
2149
2150impl GenericArgs {
2151 pub(crate) fn is_empty(&self) -> bool {
2152 match self {
2153 GenericArgs::AngleBracketed { args, constraints } => {
2154 args.is_empty() && constraints.is_empty()
2155 }
2156 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2157 GenericArgs::ReturnTypeNotation => false,
2158 }
2159 }
2160 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2161 match self {
2162 GenericArgs::AngleBracketed { constraints, .. } => {
2163 Box::new(constraints.iter().cloned())
2164 }
2165 GenericArgs::Parenthesized { output, .. } => Box::new(
2166 output
2167 .as_ref()
2168 .map(|ty| AssocItemConstraint {
2169 assoc: PathSegment {
2170 name: sym::Output,
2171 args: GenericArgs::AngleBracketed {
2172 args: ThinVec::new(),
2173 constraints: ThinVec::new(),
2174 },
2175 },
2176 kind: AssocItemConstraintKind::Equality {
2177 term: Term::Type((**ty).clone()),
2178 },
2179 })
2180 .into_iter(),
2181 ),
2182 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2183 }
2184 }
2185}
2186
2187impl<'a> IntoIterator for &'a GenericArgs {
2188 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2189 type Item = GenericArg;
2190 fn into_iter(self) -> Self::IntoIter {
2191 match self {
2192 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2193 GenericArgs::Parenthesized { inputs, .. } => {
2194 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2196 }
2197 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2198 }
2199 }
2200}
2201
2202#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2203pub(crate) struct PathSegment {
2204 pub(crate) name: Symbol,
2205 pub(crate) args: GenericArgs,
2206}
2207
2208#[derive(Clone, Debug)]
2209pub(crate) enum TypeAliasInnerType {
2210 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2211 Union { fields: Vec<Item> },
2212 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2213}
2214
2215impl TypeAliasInnerType {
2216 fn has_stripped_entries(&self) -> Option<bool> {
2217 Some(match self {
2218 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2219 Self::Union { fields } | Self::Struct { fields, .. } => {
2220 fields.iter().any(|f| f.is_stripped())
2221 }
2222 })
2223 }
2224}
2225
2226#[derive(Clone, Debug)]
2227pub(crate) struct TypeAlias {
2228 pub(crate) generics: Generics,
2229 pub(crate) type_: Type,
2230 pub(crate) inner_type: Option<TypeAliasInnerType>,
2233}
2234
2235#[derive(Clone, Debug)]
2236pub(crate) struct AssocType {
2237 pub(crate) generics: Generics,
2238 pub(crate) bounds: Vec<GenericBound>,
2239 pub(crate) type_: Option<AliasedType>,
2240}
2241
2242#[derive(Clone, Debug)]
2243pub(crate) struct AliasedType {
2244 pub(crate) type_: Type,
2245 pub(crate) middle_type: Option<Type>,
2249}
2250
2251#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2252pub(crate) struct BareFunctionDecl {
2253 pub(crate) safety: hir::Safety,
2254 pub(crate) generic_params: Vec<GenericParamDef>,
2255 pub(crate) decl: FnDecl,
2256 pub(crate) abi: ExternAbi,
2257}
2258
2259#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2260pub(crate) struct UnsafeBinderTy {
2261 pub(crate) generic_params: Vec<GenericParamDef>,
2262 pub(crate) type_: Type,
2263}
2264
2265#[derive(Clone, Debug)]
2266pub(crate) struct Static {
2267 pub(crate) type_: Box<Type>,
2268 pub(crate) mutability: Mutability,
2269 pub(crate) expr: Option<BodyId>,
2270}
2271
2272#[derive(Clone, Debug)]
2273pub(crate) struct Constant {
2274 pub(crate) generics: Generics,
2275 pub(crate) type_: Type,
2276 pub(crate) body: ConstantExpr,
2277}
2278
2279#[derive(Clone, Debug)]
2280pub(crate) struct AssocConstant {
2281 pub(crate) generics: Generics,
2282 pub(crate) type_: Type,
2283 pub(crate) body: Option<ConstantExpr>,
2284}
2285
2286#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2287pub(crate) enum Term {
2288 Type(Type),
2289 Constant(ConstantExpr),
2290}
2291
2292impl Term {
2293 pub(crate) fn ty(&self) -> Option<&Type> {
2294 if let Term::Type(ty) = self { Some(ty) } else { None }
2295 }
2296}
2297
2298impl From<Type> for Term {
2299 fn from(ty: Type) -> Self {
2300 Term::Type(ty)
2301 }
2302}
2303
2304#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2305pub(crate) enum ConstantExpr {
2306 TypeSystem { expr: Box<str> },
2312 Path { path: Box<str> },
2315 Anonymous { body: BodyId },
2319 Extern { def_id: DefId },
2321 Local { def_id: DefId, body: BodyId },
2323 Infer,
2325}
2326
2327impl ConstantExpr {
2328 pub(crate) fn rendered(&self, tcx: TyCtxt<'_>) -> String {
2329 match *self {
2330 Self::TypeSystem { ref expr } => expr.to_string(),
2331 Self::Path { ref path } => path.to_string(),
2332 Self::Extern { def_id } => print_inlined_const(tcx, def_id),
2333 Self::Local { body, .. } | Self::Anonymous { body } => {
2334 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2335 }
2336 Self::Infer => "_".to_string(),
2337 }
2338 }
2339
2340 pub(crate) fn evaluated_rendered(&self, tcx: TyCtxt<'_>) -> Option<String> {
2341 match *self {
2342 Self::TypeSystem { .. } | Self::Path { .. } | Self::Anonymous { .. } | Self::Infer => {
2343 None
2344 }
2345 Self::Extern { def_id } | Self::Local { def_id, .. } => {
2346 print_evaluated_const(tcx, def_id, true, true)
2347 }
2348 }
2349 }
2350
2351 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2352 match *self {
2353 Self::TypeSystem { .. } | Self::Extern { .. } | Self::Path { .. } | Self::Infer => {
2354 false
2355 }
2356 Self::Local { body, .. } | Self::Anonymous { body } => {
2357 is_literal_expr(tcx, body.hir_id)
2358 }
2359 }
2360 }
2361}
2362
2363#[derive(Clone, Debug)]
2364pub(crate) struct Impl {
2365 pub(crate) safety: hir::Safety,
2366 pub(crate) generics: Generics,
2367 pub(crate) trait_: Option<Path>,
2368 pub(crate) for_: Type,
2369 pub(crate) items: Vec<Item>,
2370 pub(crate) polarity: ty::ImplPolarity,
2371 pub(crate) kind: ImplKind,
2372 pub(crate) is_deprecated: bool,
2373}
2374
2375impl Impl {
2376 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2377 self.trait_
2378 .as_ref()
2379 .map(|t| t.def_id())
2380 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2381 .unwrap_or_default()
2382 }
2383
2384 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2385 matches!(self.polarity, ty::ImplPolarity::Negative)
2386 }
2387}
2388
2389#[derive(Clone, Debug)]
2390pub(crate) enum ImplKind {
2391 Normal,
2392 Auto,
2393 FakeVariadic,
2394 Blanket(Box<Type>),
2395}
2396
2397impl ImplKind {
2398 pub(crate) fn is_auto(&self) -> bool {
2399 matches!(self, ImplKind::Auto)
2400 }
2401
2402 pub(crate) fn is_blanket(&self) -> bool {
2403 matches!(self, ImplKind::Blanket(_))
2404 }
2405
2406 pub(crate) fn is_fake_variadic(&self) -> bool {
2407 matches!(self, ImplKind::FakeVariadic)
2408 }
2409
2410 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2411 match self {
2412 ImplKind::Blanket(ty) => Some(ty),
2413 _ => None,
2414 }
2415 }
2416}
2417
2418#[derive(Clone, Debug)]
2419pub(crate) struct Import {
2420 pub(crate) kind: ImportKind,
2421 pub(crate) source: ImportSource,
2423 pub(crate) should_be_displayed: bool,
2424}
2425
2426impl Import {
2427 pub(crate) fn new_simple(
2428 name: Symbol,
2429 source: ImportSource,
2430 should_be_displayed: bool,
2431 ) -> Self {
2432 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2433 }
2434
2435 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2436 Self { kind: ImportKind::Glob, source, should_be_displayed }
2437 }
2438
2439 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2440 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2441 }
2442}
2443
2444#[derive(Clone, Debug)]
2445pub(crate) enum ImportKind {
2446 Simple(Symbol),
2448 Glob,
2450}
2451
2452#[derive(Clone, Debug)]
2453pub(crate) struct ImportSource {
2454 pub(crate) path: Path,
2455 pub(crate) did: Option<DefId>,
2456}
2457
2458#[derive(Clone, Debug)]
2459pub(crate) struct DeclMacro {
2460 pub(crate) source: String,
2461 pub(crate) macro_rules: bool,
2463}
2464
2465#[derive(Clone, Debug)]
2466pub(crate) struct ProcMacro {
2467 pub(crate) kind: MacroKind,
2468 pub(crate) helpers: Vec<Symbol>,
2469}
2470
2471#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2482pub(crate) struct AssocItemConstraint {
2483 pub(crate) assoc: PathSegment,
2484 pub(crate) kind: AssocItemConstraintKind,
2485}
2486
2487#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2489pub(crate) enum AssocItemConstraintKind {
2490 Equality { term: Term },
2491 Bound { bounds: Vec<GenericBound> },
2492}
2493
2494#[cfg(target_pointer_width = "64")]
2496mod size_asserts {
2497 use rustc_data_structures::static_assert_size;
2498
2499 use super::*;
2500 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 48);
2503 static_assert_size!(GenericArg, 32);
2504 static_assert_size!(GenericArgs, 24);
2505 static_assert_size!(GenericParamDef, 40);
2506 static_assert_size!(Generics, 16);
2507 static_assert_size!(Item, 8);
2508 static_assert_size!(ItemInner, 144);
2509 static_assert_size!(ItemKind, 48);
2510 static_assert_size!(PathSegment, 32);
2511 static_assert_size!(Type, 32);
2512 }