rustdoc/html/render/
search_index.rs

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
25/// The serialized search description sharded version
26///
27/// The `index` is a JSON-encoded list of names and other information.
28///
29/// The desc has newlined descriptions, split up by size into 128KiB shards.
30/// For example, `(4, "foo\nbar\nbaz\nquux")`.
31///
32/// There is no single, optimal size for these shards, because it depends on
33/// configuration values that we can't predict or control, such as the version
34/// of HTTP used (HTTP/1.1 would work better with larger files, while HTTP/2
35/// and 3 are more agnostic), transport compression (gzip, zstd, etc), whether
36/// the search query is going to produce a large number of results or a small
37/// number, the bandwidth delay product of the network...
38///
39/// Gzipping some standard library descriptions to guess what transport
40/// compression will do, the compressed file sizes can be as small as 4.9KiB
41/// or as large as 18KiB (ignoring the final 1.9KiB shard of leftovers).
42/// A "reasonable" range for files is for them to be bigger than 1KiB,
43/// since that's about the amount of data that can be transferred in a
44/// single TCP packet, and 64KiB, the maximum amount of data that
45/// TCP can transfer in a single round trip without extensions.
46///
47/// [1]: https://en.wikipedia.org/wiki/Maximum_transmission_unit#MTUs_for_common_media
48/// [2]: https://en.wikipedia.org/wiki/Sliding_window_protocol#Basic_concept
49/// [3]: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features
50pub(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
57/// Builds the search index from the collected metadata
58pub(crate) fn build_index(
59    krate: &clean::Crate,
60    cache: &mut Cache,
61    tcx: TyCtxt<'_>,
62) -> SerializedSearchIndex {
63    // Maps from ID to position in the `crate_paths` array.
64    let mut itemid_to_pathid = FxHashMap::default();
65    let mut primitives = FxHashMap::default();
66    let mut associated_types = FxHashMap::default();
67
68    // item type, display path, re-exported internal path
69    let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)> = vec![];
70
71    // Attach all orphan items to the type's definition if the type
72    // has since been learned.
73    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    // Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
104    // we need the alias element to have an array of items.
105    let mut aliases: BTreeMap<String, Vec<usize>> = BTreeMap::new();
106
107    // Sort search index items. This improves the compressibility of the search index.
108    cache.search_index.sort_unstable_by(|k1, k2| {
109        // `sort_unstable_by_key` produces lifetime errors
110        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
111        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    // Set up alias indexes.
117    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    // Reduce `DefId` in paths into smaller sequential numbers,
124    // and prune the paths that do not appear in the index.
125    let mut lastpath = "";
126    let mut lastpathid = 0isize;
127
128    // First, on function signatures
129    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                // this bool is only used by `insert_into_map`, so it doesn't matter what we set here
177                // because Index means we've already inserted into the map
178                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                            // Re-exports only count if the name is exactly the same.
199                            // This is a size optimization, since it means we only need
200                            // to store the name once (and the path is re-used for everything
201                            // exported from this same module). It's also likely to Do
202                            // What I Mean, since if a re-export changes the name, it might
203                            // also be a change in semantic meaning.
204                            .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    // Then, on parent modules
361    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                // If this is a re-export, retain the original path.
396                // Associated items don't use this.
397                // Their parent carries the exact fqp instead.
398                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                    // Re-exports only count if the name is exactly the same.
403                    // This is a size optimization, since it means we only need
404                    // to store the name once (and the path is re-used for everything
405                    // exported from this same module). It's also likely to Do
406                    // What I Mean, since if a re-export changes the name, it might
407                    // also be a change in semantic meaning.
408                    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                            // `#[macro_export]` always exports to the crate root.
414                            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            // Omit the parent path if it is same to that of the prior item.
437            if lastpath == item.path {
438                item.path.clear();
439            } else {
440                lastpath = &item.path;
441            }
442
443            &*item
444        })
445        .collect();
446
447    // Find associated items that need disambiguators
448    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        // The String is alias name and the vec is the list of the elements with this alias.
475        //
476        // To be noted: the `usize` elements are indexes to `items`.
477        aliases: &'a BTreeMap<String, Vec<usize>>,
478        // Used when a type has more than one impl with an associated item with the same name.
479        associated_item_disambiguators: &'a Vec<(usize, String)>,
480        // A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
481        // for information on the format.
482        desc_index: String,
483        // A list of items with no description. This is eventually turned into a bitmap.
484        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            // We need to keep the order of insertion, hence why we use an `IndexMap`. Then we will
530            // insert these "extra paths" (which are paths of items from external crates) into the
531            // `full_paths` list at the end.
532            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                // It means it comes from an external crate so the item and its path will be
584                // stored into another array.
585                //
586                // `index` is put after the last `mod_paths`
587                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            // Direct exports use adjacent arrays for the current crate's items,
615            // but re-exported exact paths don't.
616            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                    // bitmasks always use 1-indexing for items, with 0 as the crate itself
699                    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", &param_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    // The index, which is actually used to search, is JSON
785    // It uses `JSON.parse(..)` to actually load, since JSON
786    // parses faster than the full JavaScript syntax.
787    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        // The type parameters are converted to generics in `simplify_fn_type`
894        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        // Not supported yet
915        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    // other kinds of type parameters are identified by their name
927    Symbol(Symbol),
928    // every argument-position impl trait is its own type parameter
929    Anonymous(isize),
930    // in a trait definition, the associated types are all bound to
931    // their own type parameter
932    AssociatedType(DefId, Symbol),
933}
934
935/// The point of this function is to lower generics and types into the simplified form that the
936/// frontend search engine can use.
937///
938/// For example, `[T, U, i32]]` where you have the bounds: `T: Display, U: Option<T>` will return
939/// `[-1, -2, i32] where -1: Display, -2: Option<-1>`. If a type parameter has no traid bound, it
940/// will still get a number. If a constraint is present but not used in the actual types, it will
941/// not be added to the map.
942///
943/// This function also works recursively.
944#[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        // FIXME: remove this whole recurse thing when the recursion bug is fixed
958        // See #59502 for the original issue.
959        return;
960    }
961
962    // First, check if it's "Self".
963    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    // If this argument is a type parameter and not a trait bound or a type, we need to look
972    // for its bounds.
973    match *arg {
974        Type::Generic(arg_s) => {
975            // First we check if the bounds are in a `where` predicate...
976            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            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
1000            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                // In return position, `impl Trait` is a unique thing.
1054                res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
1055            } else {
1056                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
1057                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            // The search index, for simplicity's sake, represents fn pointers and closures
1129            // the same way: as a tuple for the parameters, and an associated type for the
1130            // return type.
1131            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            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
1174            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
1175            //
1176            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
1177            // we will look for them but not for `T`).
1178            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            // Every trait associated type on self gets assigned to a type parameter index
1212            // this same one is used later for any appearances of these types
1213            //
1214            // for example, Iterator::next is:
1215            //
1216            //     trait Iterator {
1217            //         fn next(&mut self) -> Option<Self::Item>
1218            //     }
1219            //
1220            // Self is technically just Iterator, but we want to pretend it's more like this:
1221            //
1222            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
1223            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                            // Can't just pass stored_bounds to simplify_fn_type,
1241                            // because it also accepts rgen as a parameter.
1242                            // Instead, have it fill in this local, then copy it into the map afterward.
1243                            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
1373/// Create a fake nullary function.
1374///
1375/// Used to allow type-based search on constants and statics.
1376fn 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
1384/// Return the full list of types when bounds have been resolved.
1385///
1386/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
1387/// `[u32, Display, Option]`.
1388fn 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}