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