1pub(crate) mod encode;
2
3use std::collections::hash_map::Entry;
4use std::collections::{BTreeMap, VecDeque};
5
6use encode::{bitmap_to_string, write_vlqhex_to_string};
7use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
8use rustc_middle::ty::TyCtxt;
9use rustc_span::def_id::DefId;
10use rustc_span::sym;
11use rustc_span::symbol::{Symbol, kw};
12use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
13use thin_vec::ThinVec;
14use tracing::instrument;
15
16use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
17use crate::clean::{self, utils};
18use crate::formats::cache::{Cache, OrphanImplItem};
19use crate::formats::item_type::ItemType;
20use crate::html::format::join_with_double_colon;
21use crate::html::markdown::short_markdown_summary;
22use crate::html::render::ordered_json::OrderedJson;
23use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
24
25pub(crate) struct SerializedSearchIndex {
51 pub(crate) index: OrderedJson,
52 pub(crate) desc: Vec<(usize, String)>,
53}
54
55const DESC_INDEX_SHARD_LEN: usize = 128 * 1024;
56
57pub(crate) fn build_index(
59 krate: &clean::Crate,
60 cache: &mut Cache,
61 tcx: TyCtxt<'_>,
62) -> SerializedSearchIndex {
63 let mut itemid_to_pathid = FxHashMap::default();
65 let mut primitives = FxHashMap::default();
66 let mut associated_types = FxHashMap::default();
67
68 let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)> = vec![];
70
71 for &OrphanImplItem { impl_id, parent, ref item, ref impl_generics } in &cache.orphan_impl_items
74 {
75 if let Some((fqp, _)) = cache.paths.get(&parent) {
76 let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
77 cache.search_index.push(IndexItem {
78 ty: item.type_(),
79 defid: item.item_id.as_def_id(),
80 name: item.name.unwrap(),
81 path: join_with_double_colon(&fqp[..fqp.len() - 1]),
82 desc,
83 parent: Some(parent),
84 parent_idx: None,
85 exact_path: None,
86 impl_id,
87 search_type: get_function_type_for_search(
88 item,
89 tcx,
90 impl_generics.as_ref(),
91 Some(parent),
92 cache,
93 ),
94 aliases: item.attrs.get_doc_aliases(),
95 deprecation: item.deprecation(tcx),
96 });
97 }
98 }
99
100 let crate_doc =
101 short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache));
102
103 let mut aliases: BTreeMap<String, Vec<usize>> = BTreeMap::new();
106
107 cache.search_index.sort_unstable_by(|k1, k2| {
109 let k1 = (&k1.path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate)));
112 let k2 = (&k2.path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate)));
113 Ord::cmp(&k1, &k2)
114 });
115
116 for (i, item) in cache.search_index.iter().enumerate() {
118 for alias in &item.aliases[..] {
119 aliases.entry(alias.as_str().to_lowercase()).or_default().push(i);
120 }
121 }
122
123 let mut lastpath = "";
126 let mut lastpathid = 0isize;
127
128 let mut search_index = std::mem::take(&mut cache.search_index);
130 for item in search_index.iter_mut() {
131 fn insert_into_map<F: std::hash::Hash + Eq>(
132 map: &mut FxHashMap<F, isize>,
133 itemid: F,
134 lastpathid: &mut isize,
135 crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
136 item_type: ItemType,
137 path: &[Symbol],
138 exact_path: Option<&[Symbol]>,
139 search_unbox: bool,
140 ) -> RenderTypeId {
141 match map.entry(itemid) {
142 Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()),
143 Entry::Vacant(entry) => {
144 let pathid = *lastpathid;
145 entry.insert(pathid);
146 *lastpathid += 1;
147 crate_paths.push((
148 item_type,
149 path.to_vec(),
150 exact_path.map(|path| path.to_vec()),
151 search_unbox,
152 ));
153 RenderTypeId::Index(pathid)
154 }
155 }
156 }
157
158 fn convert_render_type_id(
159 id: RenderTypeId,
160 cache: &mut Cache,
161 itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
162 primitives: &mut FxHashMap<Symbol, isize>,
163 associated_types: &mut FxHashMap<Symbol, isize>,
164 lastpathid: &mut isize,
165 crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
166 tcx: TyCtxt<'_>,
167 ) -> Option<RenderTypeId> {
168 use crate::clean::PrimitiveType;
169 let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
170 let search_unbox = match id {
171 RenderTypeId::Mut => false,
172 RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox),
173 RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true,
174 RenderTypeId::Primitive(..) => false,
175 RenderTypeId::AssociatedType(..) => false,
176 RenderTypeId::Index(_) => false,
179 };
180 match id {
181 RenderTypeId::Mut => Some(insert_into_map(
182 primitives,
183 kw::Mut,
184 lastpathid,
185 crate_paths,
186 ItemType::Keyword,
187 &[kw::Mut],
188 None,
189 search_unbox,
190 )),
191 RenderTypeId::DefId(defid) => {
192 if let Some(&(ref fqp, item_type)) =
193 paths.get(&defid).or_else(|| external_paths.get(&defid))
194 {
195 let exact_fqp = exact_paths
196 .get(&defid)
197 .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
198 .filter(|this_fqp| this_fqp.last() == fqp.last());
205 Some(insert_into_map(
206 itemid_to_pathid,
207 ItemId::DefId(defid),
208 lastpathid,
209 crate_paths,
210 item_type,
211 fqp,
212 exact_fqp.map(|x| &x[..]).filter(|exact_fqp| exact_fqp != fqp),
213 search_unbox,
214 ))
215 } else {
216 None
217 }
218 }
219 RenderTypeId::Primitive(primitive) => {
220 let sym = primitive.as_sym();
221 Some(insert_into_map(
222 primitives,
223 sym,
224 lastpathid,
225 crate_paths,
226 ItemType::Primitive,
227 &[sym],
228 None,
229 search_unbox,
230 ))
231 }
232 RenderTypeId::Index(_) => Some(id),
233 RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
234 associated_types,
235 sym,
236 lastpathid,
237 crate_paths,
238 ItemType::AssocType,
239 &[sym],
240 None,
241 search_unbox,
242 )),
243 }
244 }
245
246 fn convert_render_type(
247 ty: &mut RenderType,
248 cache: &mut Cache,
249 itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
250 primitives: &mut FxHashMap<Symbol, isize>,
251 associated_types: &mut FxHashMap<Symbol, isize>,
252 lastpathid: &mut isize,
253 crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
254 tcx: TyCtxt<'_>,
255 ) {
256 if let Some(generics) = &mut ty.generics {
257 for item in generics {
258 convert_render_type(
259 item,
260 cache,
261 itemid_to_pathid,
262 primitives,
263 associated_types,
264 lastpathid,
265 crate_paths,
266 tcx,
267 );
268 }
269 }
270 if let Some(bindings) = &mut ty.bindings {
271 bindings.retain_mut(|(associated_type, constraints)| {
272 let converted_associated_type = convert_render_type_id(
273 *associated_type,
274 cache,
275 itemid_to_pathid,
276 primitives,
277 associated_types,
278 lastpathid,
279 crate_paths,
280 tcx,
281 );
282 let Some(converted_associated_type) = converted_associated_type else {
283 return false;
284 };
285 *associated_type = converted_associated_type;
286 for constraint in constraints {
287 convert_render_type(
288 constraint,
289 cache,
290 itemid_to_pathid,
291 primitives,
292 associated_types,
293 lastpathid,
294 crate_paths,
295 tcx,
296 );
297 }
298 true
299 });
300 }
301 let Some(id) = ty.id else {
302 assert!(ty.generics.is_some());
303 return;
304 };
305 ty.id = convert_render_type_id(
306 id,
307 cache,
308 itemid_to_pathid,
309 primitives,
310 associated_types,
311 lastpathid,
312 crate_paths,
313 tcx,
314 );
315 }
316 if let Some(search_type) = &mut item.search_type {
317 for item in &mut search_type.inputs {
318 convert_render_type(
319 item,
320 cache,
321 &mut itemid_to_pathid,
322 &mut primitives,
323 &mut associated_types,
324 &mut lastpathid,
325 &mut crate_paths,
326 tcx,
327 );
328 }
329 for item in &mut search_type.output {
330 convert_render_type(
331 item,
332 cache,
333 &mut itemid_to_pathid,
334 &mut primitives,
335 &mut associated_types,
336 &mut lastpathid,
337 &mut crate_paths,
338 tcx,
339 );
340 }
341 for constraint in &mut search_type.where_clause {
342 for trait_ in &mut constraint[..] {
343 convert_render_type(
344 trait_,
345 cache,
346 &mut itemid_to_pathid,
347 &mut primitives,
348 &mut associated_types,
349 &mut lastpathid,
350 &mut crate_paths,
351 tcx,
352 );
353 }
354 }
355 }
356 }
357
358 let Cache { ref paths, ref exact_paths, ref external_paths, .. } = *cache;
359
360 let crate_items: Vec<&IndexItem> = search_index
362 .iter_mut()
363 .map(|item| {
364 item.parent_idx =
365 item.parent.and_then(|defid| match itemid_to_pathid.entry(ItemId::DefId(defid)) {
366 Entry::Occupied(entry) => Some(*entry.get()),
367 Entry::Vacant(entry) => {
368 let pathid = lastpathid;
369 entry.insert(pathid);
370 lastpathid += 1;
371
372 if let Some(&(ref fqp, short)) = paths.get(&defid) {
373 let exact_fqp = exact_paths
374 .get(&defid)
375 .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
376 .filter(|exact_fqp| {
377 exact_fqp.last() == Some(&item.name) && *exact_fqp != fqp
378 });
379 crate_paths.push((
380 short,
381 fqp.clone(),
382 exact_fqp.cloned(),
383 utils::has_doc_flag(tcx, defid, sym::search_unbox),
384 ));
385 Some(pathid)
386 } else {
387 None
388 }
389 }
390 });
391
392 if let Some(defid) = item.defid
393 && item.parent_idx.is_none()
394 {
395 let exact_fqp = exact_paths
399 .get(&defid)
400 .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp));
401 item.exact_path = exact_fqp.and_then(|fqp| {
402 if fqp.last() != Some(&item.name) {
409 return None;
410 }
411 let path =
412 if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) {
413 tcx.crate_name(defid.krate).to_string()
415 } else {
416 if fqp.len() < 2 {
417 return None;
418 }
419 join_with_double_colon(&fqp[..fqp.len() - 1])
420 };
421 if path == item.path {
422 return None;
423 }
424 Some(path)
425 });
426 } else if let Some(parent_idx) = item.parent_idx {
427 let i = <isize as TryInto<usize>>::try_into(parent_idx).unwrap();
428 item.path = {
429 let p = &crate_paths[i].1;
430 join_with_double_colon(&p[..p.len() - 1])
431 };
432 item.exact_path =
433 crate_paths[i].2.as_ref().map(|xp| join_with_double_colon(&xp[..xp.len() - 1]));
434 }
435
436 if lastpath == item.path {
438 item.path.clear();
439 } else {
440 lastpath = &item.path;
441 }
442
443 &*item
444 })
445 .collect();
446
447 let mut associated_item_duplicates = FxHashMap::<(isize, ItemType, Symbol), usize>::default();
449
450 for &item in &crate_items {
451 if item.impl_id.is_some()
452 && let Some(parent_idx) = item.parent_idx
453 {
454 let count =
455 associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
456 *count += 1;
457 }
458 }
459
460 let associated_item_disambiguators = crate_items
461 .iter()
462 .enumerate()
463 .filter_map(|(index, item)| {
464 let impl_id = ItemId::DefId(item.impl_id?);
465 let parent_idx = item.parent_idx?;
466 let count = *associated_item_duplicates.get(&(parent_idx, item.ty, item.name))?;
467 if count > 1 { Some((index, render::get_id_for_impl(tcx, impl_id))) } else { None }
468 })
469 .collect::<Vec<_>>();
470
471 struct CrateData<'a> {
472 items: Vec<&'a IndexItem>,
473 paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
474 aliases: &'a BTreeMap<String, Vec<usize>>,
478 associated_item_disambiguators: &'a Vec<(usize, String)>,
480 desc_index: String,
483 empty_desc: Vec<u32>,
485 }
486
487 struct Paths {
488 ty: ItemType,
489 name: Symbol,
490 path: Option<usize>,
491 exact_path: Option<usize>,
492 search_unbox: bool,
493 }
494
495 impl Serialize for Paths {
496 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
497 where
498 S: Serializer,
499 {
500 let mut seq = serializer.serialize_seq(None)?;
501 seq.serialize_element(&self.ty)?;
502 seq.serialize_element(self.name.as_str())?;
503 if let Some(ref path) = self.path {
504 seq.serialize_element(path)?;
505 }
506 if let Some(ref path) = self.exact_path {
507 assert!(self.path.is_some());
508 seq.serialize_element(path)?;
509 }
510 if self.search_unbox {
511 if self.path.is_none() {
512 seq.serialize_element(&None::<u8>)?;
513 }
514 if self.exact_path.is_none() {
515 seq.serialize_element(&None::<u8>)?;
516 }
517 seq.serialize_element(&1)?;
518 }
519 seq.end()
520 }
521 }
522
523 impl Serialize for CrateData<'_> {
524 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
525 where
526 S: Serializer,
527 {
528 let mut extra_paths = FxHashMap::default();
529 let mut revert_extra_paths = FxIndexMap::default();
533 let mut mod_paths = FxHashMap::default();
534 for (index, item) in self.items.iter().enumerate() {
535 if item.path.is_empty() {
536 continue;
537 }
538 mod_paths.insert(&item.path, index);
539 }
540 let mut paths = Vec::with_capacity(self.paths.len());
541 for &(ty, ref path, ref exact, search_unbox) in &self.paths {
542 if path.len() < 2 {
543 paths.push(Paths {
544 ty,
545 name: path[0],
546 path: None,
547 exact_path: None,
548 search_unbox,
549 });
550 continue;
551 }
552 let full_path = join_with_double_colon(&path[..path.len() - 1]);
553 let full_exact_path = exact
554 .as_ref()
555 .filter(|exact| exact.last() == path.last() && exact.len() >= 2)
556 .map(|exact| join_with_double_colon(&exact[..exact.len() - 1]));
557 let exact_path = extra_paths.len() + self.items.len();
558 let exact_path = full_exact_path.as_ref().map(|full_exact_path| match extra_paths
559 .entry(full_exact_path.clone())
560 {
561 Entry::Occupied(entry) => *entry.get(),
562 Entry::Vacant(entry) => {
563 if let Some(index) = mod_paths.get(&full_exact_path) {
564 return *index;
565 }
566 entry.insert(exact_path);
567 if !revert_extra_paths.contains_key(&exact_path) {
568 revert_extra_paths.insert(exact_path, full_exact_path.clone());
569 }
570 exact_path
571 }
572 });
573 if let Some(index) = mod_paths.get(&full_path) {
574 paths.push(Paths {
575 ty,
576 name: *path.last().unwrap(),
577 path: Some(*index),
578 exact_path,
579 search_unbox,
580 });
581 continue;
582 }
583 let index = extra_paths.len() + self.items.len();
588 match extra_paths.entry(full_path.clone()) {
589 Entry::Occupied(entry) => {
590 paths.push(Paths {
591 ty,
592 name: *path.last().unwrap(),
593 path: Some(*entry.get()),
594 exact_path,
595 search_unbox,
596 });
597 }
598 Entry::Vacant(entry) => {
599 entry.insert(index);
600 if !revert_extra_paths.contains_key(&index) {
601 revert_extra_paths.insert(index, full_path);
602 }
603 paths.push(Paths {
604 ty,
605 name: *path.last().unwrap(),
606 path: Some(index),
607 exact_path,
608 search_unbox,
609 });
610 }
611 }
612 }
613
614 let mut re_exports = Vec::new();
617 for (item_index, item) in self.items.iter().enumerate() {
618 if let Some(exact_path) = item.exact_path.as_ref() {
619 if let Some(path_index) = mod_paths.get(&exact_path) {
620 re_exports.push((item_index, *path_index));
621 } else {
622 let path_index = extra_paths.len() + self.items.len();
623 let path_index = match extra_paths.entry(exact_path.clone()) {
624 Entry::Occupied(entry) => *entry.get(),
625 Entry::Vacant(entry) => {
626 entry.insert(path_index);
627 if !revert_extra_paths.contains_key(&path_index) {
628 revert_extra_paths.insert(path_index, exact_path.clone());
629 }
630 path_index
631 }
632 };
633 re_exports.push((item_index, path_index));
634 }
635 }
636 }
637
638 let mut names = Vec::with_capacity(self.items.len());
639 let mut types = String::with_capacity(self.items.len());
640 let mut full_paths = Vec::with_capacity(self.items.len());
641 let mut parents = String::with_capacity(self.items.len());
642 let mut parents_backref_queue = VecDeque::new();
643 let mut functions = String::with_capacity(self.items.len());
644 let mut deprecated = Vec::with_capacity(self.items.len());
645
646 let mut type_backref_queue = VecDeque::new();
647
648 let mut last_name = None;
649 for (index, item) in self.items.iter().enumerate() {
650 let n = item.ty as u8;
651 let c = char::from(n + b'A');
652 assert!(c <= 'z', "item types must fit within ASCII printables");
653 types.push(c);
654
655 assert_eq!(
656 item.parent.is_some(),
657 item.parent_idx.is_some(),
658 "`{}` is missing idx",
659 item.name
660 );
661 assert!(
662 parents_backref_queue.len() <= 16,
663 "the string encoding only supports 16 slots of lookback"
664 );
665 let parent: i32 = item.parent_idx.map(|x| x + 1).unwrap_or(0).try_into().unwrap();
666 if let Some(idx) = parents_backref_queue.iter().position(|p: &i32| *p == parent) {
667 parents.push(
668 char::try_from('0' as u32 + u32::try_from(idx).unwrap())
669 .expect("last possible value is '?'"),
670 );
671 } else if parent == 0 {
672 write_vlqhex_to_string(parent, &mut parents);
673 } else {
674 parents_backref_queue.push_front(parent);
675 write_vlqhex_to_string(parent, &mut parents);
676 if parents_backref_queue.len() > 16 {
677 parents_backref_queue.pop_back();
678 }
679 }
680
681 if Some(item.name.as_str()) == last_name {
682 names.push("");
683 } else {
684 names.push(item.name.as_str());
685 last_name = Some(item.name.as_str());
686 }
687
688 if !item.path.is_empty() {
689 full_paths.push((index, &item.path));
690 }
691
692 match &item.search_type {
693 Some(ty) => ty.write_to_string(&mut functions, &mut type_backref_queue),
694 None => functions.push('`'),
695 }
696
697 if item.deprecation.is_some() {
698 deprecated.push(u32::try_from(index + 1).unwrap());
700 }
701 }
702
703 for (index, path) in &revert_extra_paths {
704 full_paths.push((*index, path));
705 }
706
707 let param_names: Vec<(usize, String)> = {
708 let mut prev = Vec::new();
709 let mut result = Vec::new();
710 for (index, item) in self.items.iter().enumerate() {
711 if let Some(ty) = &item.search_type
712 && let my =
713 ty.param_names.iter().map(|sym| sym.as_str()).collect::<Vec<_>>()
714 && my != prev
715 {
716 result.push((index, my.join(",")));
717 prev = my;
718 }
719 }
720 result
721 };
722
723 let has_aliases = !self.aliases.is_empty();
724 let mut crate_data =
725 serializer.serialize_struct("CrateData", if has_aliases { 13 } else { 12 })?;
726 crate_data.serialize_field("t", &types)?;
727 crate_data.serialize_field("n", &names)?;
728 crate_data.serialize_field("q", &full_paths)?;
729 crate_data.serialize_field("i", &parents)?;
730 crate_data.serialize_field("f", &functions)?;
731 crate_data.serialize_field("D", &self.desc_index)?;
732 crate_data.serialize_field("p", &paths)?;
733 crate_data.serialize_field("r", &re_exports)?;
734 crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
735 crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?;
736 crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?;
737 crate_data.serialize_field("P", ¶m_names)?;
738 if has_aliases {
739 crate_data.serialize_field("a", &self.aliases)?;
740 }
741 crate_data.end()
742 }
743 }
744
745 let (empty_desc, desc) = {
746 let mut empty_desc = Vec::new();
747 let mut result = Vec::new();
748 let mut set = String::new();
749 let mut len: usize = 0;
750 let mut item_index: u32 = 0;
751 for desc in std::iter::once(&crate_doc).chain(crate_items.iter().map(|item| &item.desc)) {
752 if desc.is_empty() {
753 empty_desc.push(item_index);
754 item_index += 1;
755 continue;
756 }
757 if set.len() >= DESC_INDEX_SHARD_LEN {
758 result.push((len, std::mem::take(&mut set)));
759 len = 0;
760 } else if len != 0 {
761 set.push('\n');
762 }
763 set.push_str(desc);
764 len += 1;
765 item_index += 1;
766 }
767 result.push((len, std::mem::take(&mut set)));
768 (empty_desc, result)
769 };
770
771 let desc_index = {
772 let mut desc_index = String::with_capacity(desc.len() * 4);
773 for &(len, _) in desc.iter() {
774 write_vlqhex_to_string(len.try_into().unwrap(), &mut desc_index);
775 }
776 desc_index
777 };
778
779 assert_eq!(
780 crate_items.len() + 1,
781 desc.iter().map(|(len, _)| *len).sum::<usize>() + empty_desc.len()
782 );
783
784 let crate_name = krate.name(tcx);
788 let data = CrateData {
789 items: crate_items,
790 paths: crate_paths,
791 aliases: &aliases,
792 associated_item_disambiguators: &associated_item_disambiguators,
793 desc_index,
794 empty_desc,
795 };
796 let index = OrderedJson::array_unsorted([
797 OrderedJson::serialize(crate_name.as_str()).unwrap(),
798 OrderedJson::serialize(data).unwrap(),
799 ]);
800 SerializedSearchIndex { index, desc }
801}
802
803pub(crate) fn get_function_type_for_search(
804 item: &clean::Item,
805 tcx: TyCtxt<'_>,
806 impl_generics: Option<&(clean::Type, clean::Generics)>,
807 parent: Option<DefId>,
808 cache: &Cache,
809) -> Option<IndexItemFunctionType> {
810 let mut trait_info = None;
811 let impl_or_trait_generics = impl_generics.or_else(|| {
812 if let Some(def_id) = parent
813 && let Some(trait_) = cache.traits.get(&def_id)
814 && let Some((path, _)) =
815 cache.paths.get(&def_id).or_else(|| cache.external_paths.get(&def_id))
816 {
817 let path = clean::Path {
818 res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, def_id),
819 segments: path
820 .iter()
821 .map(|name| clean::PathSegment {
822 name: *name,
823 args: clean::GenericArgs::AngleBracketed {
824 args: ThinVec::new(),
825 constraints: ThinVec::new(),
826 },
827 })
828 .collect(),
829 };
830 trait_info = Some((clean::Type::Path { path }, trait_.generics.clone()));
831 Some(trait_info.as_ref().unwrap())
832 } else {
833 None
834 }
835 });
836 let (mut inputs, mut output, param_names, where_clause) = match item.kind {
837 clean::ForeignFunctionItem(ref f, _)
838 | clean::FunctionItem(ref f)
839 | clean::MethodItem(ref f, _)
840 | clean::RequiredMethodItem(ref f) => {
841 get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
842 }
843 clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
844 clean::StaticItem(ref s) => make_nullary_fn(&s.type_),
845 clean::StructFieldItem(ref t) => {
846 let Some(parent) = parent else {
847 return None;
848 };
849 let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> =
850 Default::default();
851 let output = get_index_type(t, vec![], &mut rgen);
852 let input = RenderType {
853 id: Some(RenderTypeId::DefId(parent)),
854 generics: None,
855 bindings: None,
856 };
857 (vec![input], vec![output], vec![], vec![])
858 }
859 _ => return None,
860 };
861
862 inputs.retain(|a| a.id.is_some() || a.generics.is_some());
863 output.retain(|a| a.id.is_some() || a.generics.is_some());
864
865 Some(IndexItemFunctionType { inputs, output, where_clause, param_names })
866}
867
868fn get_index_type(
869 clean_type: &clean::Type,
870 generics: Vec<RenderType>,
871 rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
872) -> RenderType {
873 RenderType {
874 id: get_index_type_id(clean_type, rgen),
875 generics: if generics.is_empty() { None } else { Some(generics) },
876 bindings: None,
877 }
878}
879
880fn get_index_type_id(
881 clean_type: &clean::Type,
882 rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
883) -> Option<RenderTypeId> {
884 use rustc_hir::def::{DefKind, Res};
885 match *clean_type {
886 clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
887 clean::DynTrait(ref bounds, _) => {
888 bounds.first().map(|b| RenderTypeId::DefId(b.trait_.def_id()))
889 }
890 clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
891 clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)),
892 clean::RawPointer(_, ref type_) => get_index_type_id(type_, rgen),
893 clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
895 clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
896 clean::BareFunction(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Fn)),
897 clean::Tuple(ref n) if n.is_empty() => {
898 Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit))
899 }
900 clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
901 clean::QPath(ref data) => {
902 if data.self_type.is_self_type()
903 && let Some(clean::Path { res: Res::Def(DefKind::Trait, trait_), .. }) = data.trait_
904 {
905 let idx = -isize::try_from(rgen.len() + 1).unwrap();
906 let (idx, _) = rgen
907 .entry(SimplifiedParam::AssociatedType(trait_, data.assoc.name))
908 .or_insert_with(|| (idx, Vec::new()));
909 Some(RenderTypeId::Index(*idx))
910 } else {
911 None
912 }
913 }
914 clean::Type::Pat(..)
916 | clean::Generic(_)
917 | clean::SelfTy
918 | clean::ImplTrait(_)
919 | clean::Infer
920 | clean::UnsafeBinder(_) => None,
921 }
922}
923
924#[derive(Clone, Copy, Eq, Hash, PartialEq)]
925enum SimplifiedParam {
926 Symbol(Symbol),
928 Anonymous(isize),
930 AssociatedType(DefId, Symbol),
933}
934
935#[instrument(level = "trace", skip(tcx, res, rgen, cache))]
945fn simplify_fn_type<'a, 'tcx>(
946 self_: Option<&'a Type>,
947 generics: &Generics,
948 arg: &'a Type,
949 tcx: TyCtxt<'tcx>,
950 recurse: usize,
951 res: &mut Vec<RenderType>,
952 rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
953 is_return: bool,
954 cache: &Cache,
955) {
956 if recurse >= 10 {
957 return;
960 }
961
962 let (is_self, arg) = if let Some(self_) = self_
964 && arg.is_self_type()
965 {
966 (true, self_)
967 } else {
968 (false, arg)
969 };
970
971 match *arg {
974 Type::Generic(arg_s) => {
975 let mut type_bounds = Vec::new();
977 for where_pred in generics.where_predicates.iter().filter(|g| match g {
978 WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
979 _ => false,
980 }) {
981 let bounds = where_pred.get_bounds().unwrap_or(&[]);
982 for bound in bounds.iter() {
983 if let Some(path) = bound.get_trait_path() {
984 let ty = Type::Path { path };
985 simplify_fn_type(
986 self_,
987 generics,
988 &ty,
989 tcx,
990 recurse + 1,
991 &mut type_bounds,
992 rgen,
993 is_return,
994 cache,
995 );
996 }
997 }
998 }
999 if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
1001 for bound in bound.get_bounds().unwrap_or(&[]) {
1002 if let Some(path) = bound.get_trait_path() {
1003 let ty = Type::Path { path };
1004 simplify_fn_type(
1005 self_,
1006 generics,
1007 &ty,
1008 tcx,
1009 recurse + 1,
1010 &mut type_bounds,
1011 rgen,
1012 is_return,
1013 cache,
1014 );
1015 }
1016 }
1017 }
1018 if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
1019 res.push(RenderType {
1020 id: Some(RenderTypeId::Index(*idx)),
1021 generics: None,
1022 bindings: None,
1023 });
1024 } else {
1025 let idx = -isize::try_from(rgen.len() + 1).unwrap();
1026 rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
1027 res.push(RenderType {
1028 id: Some(RenderTypeId::Index(idx)),
1029 generics: None,
1030 bindings: None,
1031 });
1032 }
1033 }
1034 Type::ImplTrait(ref bounds) => {
1035 let mut type_bounds = Vec::new();
1036 for bound in bounds {
1037 if let Some(path) = bound.get_trait_path() {
1038 let ty = Type::Path { path };
1039 simplify_fn_type(
1040 self_,
1041 generics,
1042 &ty,
1043 tcx,
1044 recurse + 1,
1045 &mut type_bounds,
1046 rgen,
1047 is_return,
1048 cache,
1049 );
1050 }
1051 }
1052 if is_return && !type_bounds.is_empty() {
1053 res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
1055 } else {
1056 let idx = -isize::try_from(rgen.len() + 1).unwrap();
1058 rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
1059 res.push(RenderType {
1060 id: Some(RenderTypeId::Index(idx)),
1061 generics: None,
1062 bindings: None,
1063 });
1064 }
1065 }
1066 Type::Slice(ref ty) => {
1067 let mut ty_generics = Vec::new();
1068 simplify_fn_type(
1069 self_,
1070 generics,
1071 ty,
1072 tcx,
1073 recurse + 1,
1074 &mut ty_generics,
1075 rgen,
1076 is_return,
1077 cache,
1078 );
1079 res.push(get_index_type(arg, ty_generics, rgen));
1080 }
1081 Type::Array(ref ty, _) => {
1082 let mut ty_generics = Vec::new();
1083 simplify_fn_type(
1084 self_,
1085 generics,
1086 ty,
1087 tcx,
1088 recurse + 1,
1089 &mut ty_generics,
1090 rgen,
1091 is_return,
1092 cache,
1093 );
1094 res.push(get_index_type(arg, ty_generics, rgen));
1095 }
1096 Type::Tuple(ref tys) => {
1097 let mut ty_generics = Vec::new();
1098 for ty in tys {
1099 simplify_fn_type(
1100 self_,
1101 generics,
1102 ty,
1103 tcx,
1104 recurse + 1,
1105 &mut ty_generics,
1106 rgen,
1107 is_return,
1108 cache,
1109 );
1110 }
1111 res.push(get_index_type(arg, ty_generics, rgen));
1112 }
1113 Type::BareFunction(ref bf) => {
1114 let mut ty_generics = Vec::new();
1115 for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
1116 simplify_fn_type(
1117 self_,
1118 generics,
1119 ty,
1120 tcx,
1121 recurse + 1,
1122 &mut ty_generics,
1123 rgen,
1124 is_return,
1125 cache,
1126 );
1127 }
1128 let mut ty_output = Vec::new();
1132 simplify_fn_type(
1133 self_,
1134 generics,
1135 &bf.decl.output,
1136 tcx,
1137 recurse + 1,
1138 &mut ty_output,
1139 rgen,
1140 is_return,
1141 cache,
1142 );
1143 let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
1144 res.push(RenderType {
1145 id: get_index_type_id(arg, rgen),
1146 bindings: Some(ty_bindings),
1147 generics: Some(ty_generics),
1148 });
1149 }
1150 Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
1151 let mut ty_generics = Vec::new();
1152 if mutability.is_mut() {
1153 ty_generics.push(RenderType {
1154 id: Some(RenderTypeId::Mut),
1155 generics: None,
1156 bindings: None,
1157 });
1158 }
1159 simplify_fn_type(
1160 self_,
1161 generics,
1162 type_,
1163 tcx,
1164 recurse + 1,
1165 &mut ty_generics,
1166 rgen,
1167 is_return,
1168 cache,
1169 );
1170 res.push(get_index_type(arg, ty_generics, rgen));
1171 }
1172 _ => {
1173 let mut ty_generics = Vec::new();
1179 let mut ty_constraints = Vec::new();
1180 if let Some(arg_generics) = arg.generic_args() {
1181 for ty in arg_generics.into_iter().filter_map(|param| match param {
1182 clean::GenericArg::Type(ty) => Some(ty),
1183 _ => None,
1184 }) {
1185 simplify_fn_type(
1186 self_,
1187 generics,
1188 &ty,
1189 tcx,
1190 recurse + 1,
1191 &mut ty_generics,
1192 rgen,
1193 is_return,
1194 cache,
1195 );
1196 }
1197 for constraint in arg_generics.constraints() {
1198 simplify_fn_constraint(
1199 self_,
1200 generics,
1201 &constraint,
1202 tcx,
1203 recurse + 1,
1204 &mut ty_constraints,
1205 rgen,
1206 is_return,
1207 cache,
1208 );
1209 }
1210 }
1211 if is_self
1224 && let Type::Path { path } = arg
1225 && let def_id = path.def_id()
1226 && let Some(trait_) = cache.traits.get(&def_id)
1227 && trait_.items.iter().any(|at| at.is_required_associated_type())
1228 {
1229 for assoc_ty in &trait_.items {
1230 if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) =
1231 &assoc_ty.kind
1232 && let Some(name) = assoc_ty.name
1233 {
1234 let idx = -isize::try_from(rgen.len() + 1).unwrap();
1235 let (idx, stored_bounds) = rgen
1236 .entry(SimplifiedParam::AssociatedType(def_id, name))
1237 .or_insert_with(|| (idx, Vec::new()));
1238 let idx = *idx;
1239 if stored_bounds.is_empty() {
1240 let mut type_bounds = Vec::new();
1244 for bound in bounds {
1245 if let Some(path) = bound.get_trait_path() {
1246 let ty = Type::Path { path };
1247 simplify_fn_type(
1248 self_,
1249 generics,
1250 &ty,
1251 tcx,
1252 recurse + 1,
1253 &mut type_bounds,
1254 rgen,
1255 is_return,
1256 cache,
1257 );
1258 }
1259 }
1260 let stored_bounds = &mut rgen
1261 .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
1262 .unwrap()
1263 .1;
1264 if stored_bounds.is_empty() {
1265 *stored_bounds = type_bounds;
1266 }
1267 }
1268 ty_constraints.push((
1269 RenderTypeId::AssociatedType(name),
1270 vec![RenderType {
1271 id: Some(RenderTypeId::Index(idx)),
1272 generics: None,
1273 bindings: None,
1274 }],
1275 ))
1276 }
1277 }
1278 }
1279 let id = get_index_type_id(arg, rgen);
1280 if id.is_some() || !ty_generics.is_empty() {
1281 res.push(RenderType {
1282 id,
1283 bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
1284 generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
1285 });
1286 }
1287 }
1288 }
1289}
1290
1291fn simplify_fn_constraint<'a>(
1292 self_: Option<&'a Type>,
1293 generics: &Generics,
1294 constraint: &'a clean::AssocItemConstraint,
1295 tcx: TyCtxt<'_>,
1296 recurse: usize,
1297 res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
1298 rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
1299 is_return: bool,
1300 cache: &Cache,
1301) {
1302 let mut ty_constraints = Vec::new();
1303 let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name);
1304 for param in &constraint.assoc.args {
1305 match param {
1306 clean::GenericArg::Type(arg) => simplify_fn_type(
1307 self_,
1308 generics,
1309 &arg,
1310 tcx,
1311 recurse + 1,
1312 &mut ty_constraints,
1313 rgen,
1314 is_return,
1315 cache,
1316 ),
1317 clean::GenericArg::Lifetime(_)
1318 | clean::GenericArg::Const(_)
1319 | clean::GenericArg::Infer => {}
1320 }
1321 }
1322 for constraint in constraint.assoc.args.constraints() {
1323 simplify_fn_constraint(
1324 self_,
1325 generics,
1326 &constraint,
1327 tcx,
1328 recurse + 1,
1329 res,
1330 rgen,
1331 is_return,
1332 cache,
1333 );
1334 }
1335 match &constraint.kind {
1336 clean::AssocItemConstraintKind::Equality { term } => {
1337 if let clean::Term::Type(arg) = &term {
1338 simplify_fn_type(
1339 self_,
1340 generics,
1341 arg,
1342 tcx,
1343 recurse + 1,
1344 &mut ty_constraints,
1345 rgen,
1346 is_return,
1347 cache,
1348 );
1349 }
1350 }
1351 clean::AssocItemConstraintKind::Bound { bounds } => {
1352 for bound in &bounds[..] {
1353 if let Some(path) = bound.get_trait_path() {
1354 let ty = Type::Path { path };
1355 simplify_fn_type(
1356 self_,
1357 generics,
1358 &ty,
1359 tcx,
1360 recurse + 1,
1361 &mut ty_constraints,
1362 rgen,
1363 is_return,
1364 cache,
1365 );
1366 }
1367 }
1368 }
1369 }
1370 res.push((ty_constrained_assoc, ty_constraints));
1371}
1372
1373fn make_nullary_fn(
1377 clean_type: &clean::Type,
1378) -> (Vec<RenderType>, Vec<RenderType>, Vec<Symbol>, Vec<Vec<RenderType>>) {
1379 let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
1380 let output = get_index_type(clean_type, vec![], &mut rgen);
1381 (vec![], vec![output], vec![], vec![])
1382}
1383
1384fn get_fn_inputs_and_outputs(
1389 func: &Function,
1390 tcx: TyCtxt<'_>,
1391 impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
1392 cache: &Cache,
1393) -> (Vec<RenderType>, Vec<RenderType>, Vec<Symbol>, Vec<Vec<RenderType>>) {
1394 let decl = &func.decl;
1395
1396 let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
1397
1398 let combined_generics;
1399 let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
1400 match (impl_generics.is_empty(), func.generics.is_empty()) {
1401 (true, _) => (Some(impl_self), &func.generics),
1402 (_, true) => (Some(impl_self), impl_generics),
1403 (false, false) => {
1404 let params =
1405 func.generics.params.iter().chain(&impl_generics.params).cloned().collect();
1406 let where_predicates = func
1407 .generics
1408 .where_predicates
1409 .iter()
1410 .chain(&impl_generics.where_predicates)
1411 .cloned()
1412 .collect();
1413 combined_generics = clean::Generics { params, where_predicates };
1414 (Some(impl_self), &combined_generics)
1415 }
1416 }
1417 } else {
1418 (None, &func.generics)
1419 };
1420
1421 let mut arg_types = Vec::new();
1422 for arg in decl.inputs.values.iter() {
1423 simplify_fn_type(
1424 self_,
1425 generics,
1426 &arg.type_,
1427 tcx,
1428 0,
1429 &mut arg_types,
1430 &mut rgen,
1431 false,
1432 cache,
1433 );
1434 }
1435
1436 let mut ret_types = Vec::new();
1437 simplify_fn_type(self_, generics, &decl.output, tcx, 0, &mut ret_types, &mut rgen, true, cache);
1438
1439 let mut simplified_params = rgen.into_iter().collect::<Vec<_>>();
1440 simplified_params.sort_by_key(|(_, (idx, _))| -idx);
1441 (
1442 arg_types,
1443 ret_types,
1444 simplified_params
1445 .iter()
1446 .map(|(name, (_idx, _traits))| match name {
1447 SimplifiedParam::Symbol(name) => *name,
1448 SimplifiedParam::Anonymous(_) => kw::Empty,
1449 SimplifiedParam::AssociatedType(def_id, name) => {
1450 Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name))
1451 }
1452 })
1453 .collect(),
1454 simplified_params.into_iter().map(|(_name, (_idx, traits))| traits).collect(),
1455 )
1456}