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_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
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_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    // Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
117    // we need the alias element to have an array of items.
118    let mut aliases: AliasMap = BTreeMap::new();
119
120    // Sort search index items. This improves the compressibility of the search index.
121    cache.search_index.sort_unstable_by(|k1, k2| {
122        // `sort_unstable_by_key` produces lifetime errors
123        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
124        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    // Set up alias indexes.
130    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    // Reduce `DefId` in paths into smaller sequential numbers,
137    // and prune the paths that do not appear in the index.
138    let mut lastpath = "";
139    let mut lastpathid = 0isize;
140
141    // First, on function signatures
142    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                // this bool is only used by `insert_into_map`, so it doesn't matter what we set here
190                // because Index means we've already inserted into the map
191                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                            // Re-exports only count if the name is exactly the same.
212                            // This is a size optimization, since it means we only need
213                            // to store the name once (and the path is re-used for everything
214                            // exported from this same module). It's also likely to Do
215                            // What I Mean, since if a re-export changes the name, it might
216                            // also be a change in semantic meaning.
217                            .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    // Then, on parent modules
374    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                // If this is a re-export, retain the original path.
409                // Associated items don't use this.
410                // Their parent carries the exact fqp instead.
411                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                    // Re-exports only count if the name is exactly the same.
416                    // This is a size optimization, since it means we only need
417                    // to store the name once (and the path is re-used for everything
418                    // exported from this same module). It's also likely to Do
419                    // What I Mean, since if a re-export changes the name, it might
420                    // also be a change in semantic meaning.
421                    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                            // `#[macro_export]` always exports to the crate root.
427                            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            // Omit the parent path if it is same to that of the prior item.
450            if lastpath == item.path {
451                item.path.clear();
452            } else {
453                lastpath = &item.path;
454            }
455
456            &*item
457        })
458        .collect();
459
460    // Find associated items that need disambiguators
461    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        // The String is alias name and the vec is the list of the elements with this alias.
488        //
489        // To be noted: the `usize` elements are indexes to `items`.
490        aliases: &'a AliasMap,
491        // Used when a type has more than one impl with an associated item with the same name.
492        associated_item_disambiguators: &'a Vec<(usize, String)>,
493        // A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
494        // for information on the format.
495        desc_index: String,
496        // A list of items with no description. This is eventually turned into a bitmap.
497        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            // We need to keep the order of insertion, hence why we use an `IndexMap`. Then we will
543            // insert these "extra paths" (which are paths of items from external crates) into the
544            // `full_paths` list at the end.
545            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                // It means it comes from an external crate so the item and its path will be
597                // stored into another array.
598                //
599                // `index` is put after the last `mod_paths`
600                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            // Direct exports use adjacent arrays for the current crate's items,
628            // but re-exported exact paths don't.
629            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                    // bitmasks always use 1-indexing for items, with 0 as the crate itself
712                    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", &param_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    // The index, which is actually used to search, is JSON
801    // It uses `JSON.parse(..)` to actually load, since JSON
802    // parses faster than the full JavaScript syntax.
803    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        // The type parameters are converted to generics in `simplify_fn_type`
907        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        // Not supported yet
928        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    // other kinds of type parameters are identified by their name
940    Symbol(Symbol),
941    // every argument-position impl trait is its own type parameter
942    Anonymous(isize),
943    // in a trait definition, the associated types are all bound to
944    // their own type parameter
945    AssociatedType(DefId, Symbol),
946}
947
948/// The point of this function is to lower generics and types into the simplified form that the
949/// frontend search engine can use.
950///
951/// For example, `[T, U, i32]]` where you have the bounds: `T: Display, U: Option<T>` will return
952/// `[-1, -2, i32] where -1: Display, -2: Option<-1>`. If a type parameter has no traid bound, it
953/// will still get a number. If a constraint is present but not used in the actual types, it will
954/// not be added to the map.
955///
956/// This function also works recursively.
957#[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        // FIXME: remove this whole recurse thing when the recursion bug is fixed
971        // See #59502 for the original issue.
972        return;
973    }
974
975    // First, check if it's "Self".
976    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    // If this argument is a type parameter and not a trait bound or a type, we need to look
985    // for its bounds.
986    match *arg {
987        Type::Generic(arg_s) => {
988            // First we check if the bounds are in a `where` predicate...
989            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            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
1013            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                // In return position, `impl Trait` is a unique thing.
1067                res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
1068            } else {
1069                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
1070                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            // The search index, for simplicity's sake, represents fn pointers and closures
1142            // the same way: as a tuple for the parameters, and an associated type for the
1143            // return type.
1144            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            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
1187            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
1188            //
1189            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
1190            // we will look for them but not for `T`).
1191            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            // Every trait associated type on self gets assigned to a type parameter index
1225            // this same one is used later for any appearances of these types
1226            //
1227            // for example, Iterator::next is:
1228            //
1229            //     trait Iterator {
1230            //         fn next(&mut self) -> Option<Self::Item>
1231            //     }
1232            //
1233            // Self is technically just Iterator, but we want to pretend it's more like this:
1234            //
1235            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
1236            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                            // Can't just pass stored_bounds to simplify_fn_type,
1254                            // because it also accepts rgen as a parameter.
1255                            // Instead, have it fill in this local, then copy it into the map afterward.
1256                            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
1386/// Create a fake nullary function.
1387///
1388/// Used to allow type-based search on constants and statics.
1389fn 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
1397/// Return the full list of types when bounds have been resolved.
1398///
1399/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
1400/// `[u32, Display, Option]`.
1401fn 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            &param.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}