rustdoc/html/render/
search_index.rs

1pub(crate) mod encode;
2mod serde;
3
4use std::collections::BTreeSet;
5use std::collections::hash_map::Entry;
6use std::path::Path;
7use std::string::FromUtf8Error;
8use std::{io, iter};
9
10use ::serde::de::{self, Deserializer, Error as _};
11use ::serde::ser::{SerializeSeq, Serializer};
12use ::serde::{Deserialize, Serialize};
13use rustc_ast::join_path_syms;
14use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
15use rustc_data_structures::thin_vec::ThinVec;
16use rustc_hir::attrs::AttributeKind;
17use rustc_hir::find_attr;
18use rustc_middle::ty::TyCtxt;
19use rustc_span::def_id::DefId;
20use rustc_span::sym;
21use rustc_span::symbol::{Symbol, kw};
22use stringdex::internals as stringdex_internals;
23use tracing::instrument;
24
25use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
26use crate::clean::{self, utils};
27use crate::config::ShouldMerge;
28use crate::error::Error;
29use crate::formats::cache::{Cache, OrphanImplItem};
30use crate::formats::item_type::ItemType;
31use crate::html::markdown::short_markdown_summary;
32use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
33
34#[derive(Clone, Debug, Default, Deserialize, Serialize)]
35pub(crate) struct SerializedSearchIndex {
36    // data from disk
37    names: Vec<String>,
38    path_data: Vec<Option<PathData>>,
39    entry_data: Vec<Option<EntryData>>,
40    descs: Vec<String>,
41    function_data: Vec<Option<IndexItemFunctionType>>,
42    alias_pointers: Vec<Option<usize>>,
43    // inverted index for concrete types and generics
44    type_data: Vec<Option<TypeData>>,
45    /// inverted index of generics
46    ///
47    /// - The outermost list has one entry per alpha-normalized generic.
48    ///
49    /// - The second layer is sorted by number of types that appear in the
50    ///   type signature. The search engine iterates over these in order from
51    ///   smallest to largest. Functions with less stuff in their type
52    ///   signature are more likely to be what the user wants, because we never
53    ///   show functions that are *missing* parts of the query, so removing..
54    ///
55    /// - The final layer is the list of functions.
56    generic_inverted_index: Vec<Vec<Vec<u32>>>,
57    // generated in-memory backref cache
58    #[serde(skip)]
59    crate_paths_index: FxHashMap<(ItemType, Vec<Symbol>), usize>,
60}
61
62impl SerializedSearchIndex {
63    fn load(doc_root: &Path, resource_suffix: &str) -> Result<SerializedSearchIndex, Error> {
64        let mut names: Vec<String> = Vec::new();
65        let mut path_data: Vec<Option<PathData>> = Vec::new();
66        let mut entry_data: Vec<Option<EntryData>> = Vec::new();
67        let mut descs: Vec<String> = Vec::new();
68        let mut function_data: Vec<Option<IndexItemFunctionType>> = Vec::new();
69        let mut type_data: Vec<Option<TypeData>> = Vec::new();
70        let mut alias_pointers: Vec<Option<usize>> = Vec::new();
71
72        let mut generic_inverted_index: Vec<Vec<Vec<u32>>> = Vec::new();
73
74        match perform_read_strings(resource_suffix, doc_root, "name", &mut names) {
75            Ok(()) => {
76                perform_read_serde(resource_suffix, doc_root, "path", &mut path_data)?;
77                perform_read_serde(resource_suffix, doc_root, "entry", &mut entry_data)?;
78                perform_read_strings(resource_suffix, doc_root, "desc", &mut descs)?;
79                perform_read_serde(resource_suffix, doc_root, "function", &mut function_data)?;
80                perform_read_serde(resource_suffix, doc_root, "type", &mut type_data)?;
81                perform_read_serde(resource_suffix, doc_root, "alias", &mut alias_pointers)?;
82                perform_read_postings(
83                    resource_suffix,
84                    doc_root,
85                    "generic_inverted_index",
86                    &mut generic_inverted_index,
87                )?;
88            }
89            Err(_) => {
90                names.clear();
91            }
92        }
93        fn perform_read_strings(
94            resource_suffix: &str,
95            doc_root: &Path,
96            column_name: &str,
97            column: &mut Vec<String>,
98        ) -> Result<(), Error> {
99            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
100            let column_path = doc_root.join(format!("search.index/{column_name}/"));
101
102            let mut consume = |_, cell: &[u8]| {
103                column.push(String::from_utf8(cell.to_vec())?);
104                Ok::<_, FromUtf8Error>(())
105            };
106
107            stringdex_internals::read_data_from_disk_column(
108                root_path,
109                column_name.as_bytes(),
110                column_path.clone(),
111                &mut consume,
112            )
113            .map_err(|error| Error {
114                file: column_path,
115                error: format!("failed to read column from disk: {error}"),
116            })
117        }
118        fn perform_read_serde(
119            resource_suffix: &str,
120            doc_root: &Path,
121            column_name: &str,
122            column: &mut Vec<Option<impl for<'de> Deserialize<'de> + 'static>>,
123        ) -> Result<(), Error> {
124            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
125            let column_path = doc_root.join(format!("search.index/{column_name}/"));
126
127            let mut consume = |_, cell: &[u8]| {
128                if cell.is_empty() {
129                    column.push(None);
130                } else {
131                    column.push(Some(serde_json::from_slice(cell)?));
132                }
133                Ok::<_, serde_json::Error>(())
134            };
135
136            stringdex_internals::read_data_from_disk_column(
137                root_path,
138                column_name.as_bytes(),
139                column_path.clone(),
140                &mut consume,
141            )
142            .map_err(|error| Error {
143                file: column_path,
144                error: format!("failed to read column from disk: {error}"),
145            })
146        }
147        fn perform_read_postings(
148            resource_suffix: &str,
149            doc_root: &Path,
150            column_name: &str,
151            column: &mut Vec<Vec<Vec<u32>>>,
152        ) -> Result<(), Error> {
153            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
154            let column_path = doc_root.join(format!("search.index/{column_name}/"));
155
156            fn consumer(
157                column: &mut Vec<Vec<Vec<u32>>>,
158            ) -> impl FnMut(u32, &[u8]) -> io::Result<()> {
159                |_, cell| {
160                    let mut postings = Vec::new();
161                    encode::read_postings_from_string(&mut postings, cell);
162                    column.push(postings);
163                    Ok(())
164                }
165            }
166
167            stringdex_internals::read_data_from_disk_column(
168                root_path,
169                column_name.as_bytes(),
170                column_path.clone(),
171                &mut consumer(column),
172            )
173            .map_err(|error| Error {
174                file: column_path,
175                error: format!("failed to read column from disk: {error}"),
176            })
177        }
178
179        assert_eq!(names.len(), path_data.len());
180        assert_eq!(path_data.len(), entry_data.len());
181        assert_eq!(entry_data.len(), descs.len());
182        assert_eq!(descs.len(), function_data.len());
183        assert_eq!(function_data.len(), type_data.len());
184        assert_eq!(type_data.len(), alias_pointers.len());
185
186        // generic_inverted_index is not the same length as other columns,
187        // because it's actually a completely different set of objects
188
189        let mut crate_paths_index: FxHashMap<(ItemType, Vec<Symbol>), usize> = FxHashMap::default();
190        for (i, (name, path_data)) in names.iter().zip(path_data.iter()).enumerate() {
191            if let Some(path_data) = path_data {
192                let full_path = if path_data.module_path.is_empty() {
193                    vec![Symbol::intern(name)]
194                } else {
195                    let mut full_path = path_data.module_path.to_vec();
196                    full_path.push(Symbol::intern(name));
197                    full_path
198                };
199                crate_paths_index.insert((path_data.ty, full_path), i);
200            }
201        }
202
203        Ok(SerializedSearchIndex {
204            names,
205            path_data,
206            entry_data,
207            descs,
208            function_data,
209            type_data,
210            alias_pointers,
211            generic_inverted_index,
212            crate_paths_index,
213        })
214    }
215    fn push(
216        &mut self,
217        name: String,
218        path_data: Option<PathData>,
219        entry_data: Option<EntryData>,
220        desc: String,
221        function_data: Option<IndexItemFunctionType>,
222        type_data: Option<TypeData>,
223        alias_pointer: Option<usize>,
224    ) -> usize {
225        let index = self.names.len();
226        assert_eq!(self.names.len(), self.path_data.len());
227        if let Some(path_data) = &path_data
228            && let name = Symbol::intern(&name)
229            && let fqp = if path_data.module_path.is_empty() {
230                vec![name]
231            } else {
232                let mut v = path_data.module_path.clone();
233                v.push(name);
234                v
235            }
236            && let Some(&other_path) = self.crate_paths_index.get(&(path_data.ty, fqp))
237            && self.path_data.get(other_path).map_or(false, Option::is_some)
238        {
239            self.path_data.push(None);
240        } else {
241            self.path_data.push(path_data);
242        }
243        self.names.push(name);
244        assert_eq!(self.entry_data.len(), self.descs.len());
245        self.entry_data.push(entry_data);
246        assert_eq!(self.descs.len(), self.function_data.len());
247        self.descs.push(desc);
248        assert_eq!(self.function_data.len(), self.type_data.len());
249        self.function_data.push(function_data);
250        assert_eq!(self.type_data.len(), self.alias_pointers.len());
251        self.type_data.push(type_data);
252        self.alias_pointers.push(alias_pointer);
253        index
254    }
255    /// Add potential search result to the database and return the row ID.
256    ///
257    /// The returned ID can be used to attach more data to the search result.
258    fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize {
259        let fqp = if let Some(module_path_index) = entry_data.module_path {
260            self.path_data[module_path_index]
261                .as_ref()
262                .unwrap()
263                .module_path
264                .iter()
265                .copied()
266                .chain([Symbol::intern(&self.names[module_path_index]), name])
267                .collect()
268        } else {
269            vec![name]
270        };
271        // If a path with the same name already exists, but no entry does,
272        // we can fill in the entry without having to allocate a new row ID.
273        //
274        // Because paths and entries both share the same index, using the same
275        // ID saves space by making the tree smaller.
276        if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp))
277            && self.entry_data[other_path].is_none()
278            && self.descs[other_path].is_empty()
279        {
280            self.entry_data[other_path] = Some(entry_data);
281            self.descs[other_path] = desc;
282            other_path
283        } else {
284            self.push(name.as_str().to_string(), None, Some(entry_data), desc, None, None, None)
285        }
286    }
287    fn push_path(&mut self, name: String, path_data: PathData) -> usize {
288        self.push(name, Some(path_data), None, String::new(), None, None, None)
289    }
290    fn push_type(&mut self, name: String, path_data: PathData, type_data: TypeData) -> usize {
291        self.push(name, Some(path_data), None, String::new(), None, Some(type_data), None)
292    }
293    fn push_alias(&mut self, name: String, alias_pointer: usize) -> usize {
294        self.push(name, None, None, String::new(), None, None, Some(alias_pointer))
295    }
296
297    fn get_id_by_module_path(&mut self, path: &[Symbol]) -> usize {
298        let ty = if path.len() == 1 { ItemType::ExternCrate } else { ItemType::Module };
299        match self.crate_paths_index.entry((ty, path.to_vec())) {
300            Entry::Occupied(index) => *index.get(),
301            Entry::Vacant(slot) => {
302                slot.insert(self.path_data.len());
303                let (name, module_path) = path.split_last().unwrap();
304                self.push_path(
305                    name.as_str().to_string(),
306                    PathData { ty, module_path: module_path.to_vec(), exact_module_path: None },
307                )
308            }
309        }
310    }
311
312    pub(crate) fn union(mut self, other: &SerializedSearchIndex) -> SerializedSearchIndex {
313        let other_entryid_offset = self.names.len();
314        let mut map_other_pathid_to_self_pathid = Vec::new();
315        let mut skips = FxHashSet::default();
316        for (other_pathid, other_path_data) in other.path_data.iter().enumerate() {
317            if let Some(other_path_data) = other_path_data {
318                let name = Symbol::intern(&other.names[other_pathid]);
319                let fqp =
320                    other_path_data.module_path.iter().copied().chain(iter::once(name)).collect();
321                let self_pathid = other_entryid_offset + other_pathid;
322                let self_pathid = match self.crate_paths_index.entry((other_path_data.ty, fqp)) {
323                    Entry::Vacant(slot) => {
324                        slot.insert(self_pathid);
325                        self_pathid
326                    }
327                    Entry::Occupied(existing_entryid) => {
328                        skips.insert(other_pathid);
329                        let self_pathid = *existing_entryid.get();
330                        let new_type_data = match (
331                            self.type_data[self_pathid].take(),
332                            other.type_data[other_pathid].as_ref(),
333                        ) {
334                            (Some(self_type_data), None) => Some(self_type_data),
335                            (None, Some(other_type_data)) => Some(TypeData {
336                                search_unbox: other_type_data.search_unbox,
337                                inverted_function_inputs_index: other_type_data
338                                    .inverted_function_inputs_index
339                                    .iter()
340                                    .cloned()
341                                    .map(|mut list: Vec<u32>| {
342                                        for fnid in &mut list {
343                                            assert!(
344                                                other.function_data
345                                                    [usize::try_from(*fnid).unwrap()]
346                                                .is_some(),
347                                            );
348                                            // this is valid because we call `self.push()` once, exactly, for every entry,
349                                            // even if we're just pushing a tombstone
350                                            *fnid += u32::try_from(other_entryid_offset).unwrap();
351                                        }
352                                        list
353                                    })
354                                    .collect(),
355                                inverted_function_output_index: other_type_data
356                                    .inverted_function_output_index
357                                    .iter()
358                                    .cloned()
359                                    .map(|mut list: Vec<u32>| {
360                                        for fnid in &mut list {
361                                            assert!(
362                                                other.function_data
363                                                    [usize::try_from(*fnid).unwrap()]
364                                                .is_some(),
365                                            );
366                                            // this is valid because we call `self.push()` once, exactly, for every entry,
367                                            // even if we're just pushing a tombstone
368                                            *fnid += u32::try_from(other_entryid_offset).unwrap();
369                                        }
370                                        list
371                                    })
372                                    .collect(),
373                            }),
374                            (Some(mut self_type_data), Some(other_type_data)) => {
375                                for (size, other_list) in other_type_data
376                                    .inverted_function_inputs_index
377                                    .iter()
378                                    .enumerate()
379                                {
380                                    while self_type_data.inverted_function_inputs_index.len()
381                                        <= size
382                                    {
383                                        self_type_data
384                                            .inverted_function_inputs_index
385                                            .push(Vec::new());
386                                    }
387                                    self_type_data.inverted_function_inputs_index[size].extend(
388                                        other_list.iter().copied().map(|fnid| {
389                                            assert!(
390                                                other.function_data[usize::try_from(fnid).unwrap()]
391                                                    .is_some(),
392                                            );
393                                            // this is valid because we call `self.push()` once, exactly, for every entry,
394                                            // even if we're just pushing a tombstone
395                                            fnid + u32::try_from(other_entryid_offset).unwrap()
396                                        }),
397                                    )
398                                }
399                                for (size, other_list) in other_type_data
400                                    .inverted_function_output_index
401                                    .iter()
402                                    .enumerate()
403                                {
404                                    while self_type_data.inverted_function_output_index.len()
405                                        <= size
406                                    {
407                                        self_type_data
408                                            .inverted_function_output_index
409                                            .push(Vec::new());
410                                    }
411                                    self_type_data.inverted_function_output_index[size].extend(
412                                        other_list.iter().copied().map(|fnid| {
413                                            assert!(
414                                                other.function_data[usize::try_from(fnid).unwrap()]
415                                                    .is_some(),
416                                            );
417                                            // this is valid because we call `self.push()` once, exactly, for every entry,
418                                            // even if we're just pushing a tombstone
419                                            fnid + u32::try_from(other_entryid_offset).unwrap()
420                                        }),
421                                    )
422                                }
423                                Some(self_type_data)
424                            }
425                            (None, None) => None,
426                        };
427                        self.type_data[self_pathid] = new_type_data;
428                        self_pathid
429                    }
430                };
431                map_other_pathid_to_self_pathid.push(self_pathid);
432            } else {
433                // if this gets used, we want it to crash
434                // this should be impossible as a valid index, since some of the
435                // memory must be used for stuff other than the list
436                map_other_pathid_to_self_pathid.push(!0);
437            }
438        }
439        for other_entryid in 0..other.names.len() {
440            if skips.contains(&other_entryid) {
441                // we push tombstone entries to keep the IDs lined up
442                self.push(String::new(), None, None, String::new(), None, None, None);
443            } else {
444                self.push(
445                    other.names[other_entryid].clone(),
446                    other.path_data[other_entryid].clone(),
447                    other.entry_data[other_entryid].as_ref().map(|other_entry_data| EntryData {
448                        parent: other_entry_data
449                            .parent
450                            .map(|parent| map_other_pathid_to_self_pathid[parent])
451                            .clone(),
452                        module_path: other_entry_data
453                            .module_path
454                            .map(|path| map_other_pathid_to_self_pathid[path])
455                            .clone(),
456                        exact_module_path: other_entry_data
457                            .exact_module_path
458                            .map(|exact_path| map_other_pathid_to_self_pathid[exact_path])
459                            .clone(),
460                        krate: map_other_pathid_to_self_pathid[other_entry_data.krate],
461                        ..other_entry_data.clone()
462                    }),
463                    other.descs[other_entryid].clone(),
464                    other.function_data[other_entryid].clone().map(|mut func| {
465                        fn map_fn_sig_item(
466                            map_other_pathid_to_self_pathid: &Vec<usize>,
467                            ty: &mut RenderType,
468                        ) {
469                            match ty.id {
470                                None => {}
471                                Some(RenderTypeId::Index(generic)) if generic < 0 => {}
472                                Some(RenderTypeId::Index(id)) => {
473                                    let id = usize::try_from(id).unwrap();
474                                    let id = map_other_pathid_to_self_pathid[id];
475                                    assert!(id != !0);
476                                    ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
477                                }
478                                _ => unreachable!(),
479                            }
480                            if let Some(generics) = &mut ty.generics {
481                                for generic in generics {
482                                    map_fn_sig_item(map_other_pathid_to_self_pathid, generic);
483                                }
484                            }
485                            if let Some(bindings) = &mut ty.bindings {
486                                for (param, constraints) in bindings {
487                                    *param = match *param {
488                                        param @ RenderTypeId::Index(generic) if generic < 0 => {
489                                            param
490                                        }
491                                        RenderTypeId::Index(id) => {
492                                            let id = usize::try_from(id).unwrap();
493                                            let id = map_other_pathid_to_self_pathid[id];
494                                            assert!(id != !0);
495                                            RenderTypeId::Index(isize::try_from(id).unwrap())
496                                        }
497                                        _ => unreachable!(),
498                                    };
499                                    for constraint in constraints {
500                                        map_fn_sig_item(
501                                            map_other_pathid_to_self_pathid,
502                                            constraint,
503                                        );
504                                    }
505                                }
506                            }
507                        }
508                        for input in &mut func.inputs {
509                            map_fn_sig_item(&map_other_pathid_to_self_pathid, input);
510                        }
511                        for output in &mut func.output {
512                            map_fn_sig_item(&map_other_pathid_to_self_pathid, output);
513                        }
514                        for clause in &mut func.where_clause {
515                            for entry in clause {
516                                map_fn_sig_item(&map_other_pathid_to_self_pathid, entry);
517                            }
518                        }
519                        func
520                    }),
521                    other.type_data[other_entryid].as_ref().map(|type_data| TypeData {
522                        inverted_function_inputs_index: type_data
523                            .inverted_function_inputs_index
524                            .iter()
525                            .cloned()
526                            .map(|mut list| {
527                                for fnid in &mut list {
528                                    assert!(
529                                        other.function_data[usize::try_from(*fnid).unwrap()]
530                                            .is_some(),
531                                    );
532                                    // this is valid because we call `self.push()` once, exactly, for every entry,
533                                    // even if we're just pushing a tombstone
534                                    *fnid += u32::try_from(other_entryid_offset).unwrap();
535                                }
536                                list
537                            })
538                            .collect(),
539                        inverted_function_output_index: type_data
540                            .inverted_function_output_index
541                            .iter()
542                            .cloned()
543                            .map(|mut list| {
544                                for fnid in &mut list {
545                                    assert!(
546                                        other.function_data[usize::try_from(*fnid).unwrap()]
547                                            .is_some(),
548                                    );
549                                    // this is valid because we call `self.push()` once, exactly, for every entry,
550                                    // even if we're just pushing a tombstone
551                                    *fnid += u32::try_from(other_entryid_offset).unwrap();
552                                }
553                                list
554                            })
555                            .collect(),
556                        search_unbox: type_data.search_unbox,
557                    }),
558                    other.alias_pointers[other_entryid]
559                        .map(|alias_pointer| alias_pointer + other_entryid_offset),
560                );
561            }
562        }
563        if other.generic_inverted_index.len() > self.generic_inverted_index.len() {
564            self.generic_inverted_index.resize(other.generic_inverted_index.len(), Vec::new());
565        }
566        for (other_generic_inverted_index, self_generic_inverted_index) in
567            iter::zip(&other.generic_inverted_index, &mut self.generic_inverted_index)
568        {
569            if other_generic_inverted_index.len() > self_generic_inverted_index.len() {
570                self_generic_inverted_index.resize(other_generic_inverted_index.len(), Vec::new());
571            }
572            for (other_list, self_list) in
573                iter::zip(other_generic_inverted_index, self_generic_inverted_index)
574            {
575                self_list.extend(
576                    other_list
577                        .iter()
578                        .copied()
579                        .map(|fnid| fnid + u32::try_from(other_entryid_offset).unwrap()),
580                );
581            }
582        }
583        self
584    }
585
586    pub(crate) fn sort(self) -> SerializedSearchIndex {
587        let mut idlist: Vec<usize> = (0..self.names.len()).collect();
588        // nameless entries are tombstones, and will be removed after sorting
589        // sort shorter names first, so that we can present them in order out of search.js
590        idlist.sort_by_key(|&id| {
591            (
592                self.names[id].is_empty(),
593                self.names[id].len(),
594                &self.names[id],
595                self.entry_data[id].as_ref().map_or("", |entry| self.names[entry.krate].as_str()),
596                self.path_data[id].as_ref().map_or(&[][..], |entry| &entry.module_path[..]),
597            )
598        });
599        let map = FxHashMap::from_iter(
600            idlist.iter().enumerate().map(|(new_id, &old_id)| (old_id, new_id)),
601        );
602        let mut new = SerializedSearchIndex::default();
603        for &id in &idlist {
604            if self.names[id].is_empty() {
605                break;
606            }
607            new.push(
608                self.names[id].clone(),
609                self.path_data[id].clone(),
610                self.entry_data[id].as_ref().map(
611                    |EntryData {
612                         krate,
613                         ty,
614                         module_path,
615                         exact_module_path,
616                         parent,
617                         trait_parent,
618                         deprecated,
619                         associated_item_disambiguator,
620                     }| EntryData {
621                        krate: *map.get(krate).unwrap(),
622                        ty: *ty,
623                        module_path: module_path.and_then(|path_id| map.get(&path_id).copied()),
624                        exact_module_path: exact_module_path
625                            .and_then(|path_id| map.get(&path_id).copied()),
626                        parent: parent.and_then(|path_id| map.get(&path_id).copied()),
627                        trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()),
628                        deprecated: *deprecated,
629                        associated_item_disambiguator: associated_item_disambiguator.clone(),
630                    },
631                ),
632                self.descs[id].clone(),
633                self.function_data[id].clone().map(|mut func| {
634                    fn map_fn_sig_item(map: &FxHashMap<usize, usize>, ty: &mut RenderType) {
635                        match ty.id {
636                            None => {}
637                            Some(RenderTypeId::Index(generic)) if generic < 0 => {}
638                            Some(RenderTypeId::Index(id)) => {
639                                let id = usize::try_from(id).unwrap();
640                                let id = *map.get(&id).unwrap();
641                                assert!(id != !0);
642                                ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
643                            }
644                            _ => unreachable!(),
645                        }
646                        if let Some(generics) = &mut ty.generics {
647                            for generic in generics {
648                                map_fn_sig_item(map, generic);
649                            }
650                        }
651                        if let Some(bindings) = &mut ty.bindings {
652                            for (param, constraints) in bindings {
653                                *param = match *param {
654                                    param @ RenderTypeId::Index(generic) if generic < 0 => param,
655                                    RenderTypeId::Index(id) => {
656                                        let id = usize::try_from(id).unwrap();
657                                        let id = *map.get(&id).unwrap();
658                                        assert!(id != !0);
659                                        RenderTypeId::Index(isize::try_from(id).unwrap())
660                                    }
661                                    _ => unreachable!(),
662                                };
663                                for constraint in constraints {
664                                    map_fn_sig_item(map, constraint);
665                                }
666                            }
667                        }
668                    }
669                    for input in &mut func.inputs {
670                        map_fn_sig_item(&map, input);
671                    }
672                    for output in &mut func.output {
673                        map_fn_sig_item(&map, output);
674                    }
675                    for clause in &mut func.where_clause {
676                        for entry in clause {
677                            map_fn_sig_item(&map, entry);
678                        }
679                    }
680                    func
681                }),
682                self.type_data[id].as_ref().map(
683                    |TypeData {
684                         search_unbox,
685                         inverted_function_inputs_index,
686                         inverted_function_output_index,
687                     }| {
688                        let inverted_function_inputs_index: Vec<Vec<u32>> =
689                            inverted_function_inputs_index
690                                .iter()
691                                .cloned()
692                                .map(|mut list| {
693                                    for id in &mut list {
694                                        *id = u32::try_from(
695                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
696                                        )
697                                        .unwrap();
698                                    }
699                                    list.sort();
700                                    list
701                                })
702                                .collect();
703                        let inverted_function_output_index: Vec<Vec<u32>> =
704                            inverted_function_output_index
705                                .iter()
706                                .cloned()
707                                .map(|mut list| {
708                                    for id in &mut list {
709                                        *id = u32::try_from(
710                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
711                                        )
712                                        .unwrap();
713                                    }
714                                    list.sort();
715                                    list
716                                })
717                                .collect();
718                        TypeData {
719                            search_unbox: *search_unbox,
720                            inverted_function_inputs_index,
721                            inverted_function_output_index,
722                        }
723                    },
724                ),
725                self.alias_pointers[id].and_then(|alias| {
726                    if self.names[alias].is_empty() { None } else { map.get(&alias).copied() }
727                }),
728            );
729        }
730        new.generic_inverted_index = self
731            .generic_inverted_index
732            .into_iter()
733            .map(|mut postings| {
734                for list in postings.iter_mut() {
735                    let mut new_list: Vec<u32> = list
736                        .iter()
737                        .copied()
738                        .filter_map(|id| u32::try_from(*map.get(&usize::try_from(id).ok()?)?).ok())
739                        .collect();
740                    new_list.sort();
741                    *list = new_list;
742                }
743                postings
744            })
745            .collect();
746        new
747    }
748
749    pub(crate) fn write_to(self, doc_root: &Path, resource_suffix: &str) -> Result<(), Error> {
750        let SerializedSearchIndex {
751            names,
752            path_data,
753            entry_data,
754            descs,
755            function_data,
756            type_data,
757            alias_pointers,
758            generic_inverted_index,
759            crate_paths_index: _,
760        } = self;
761        let mut serialized_root = Vec::new();
762        serialized_root.extend_from_slice(br#"rr_('{"normalizedName":{"I":""#);
763        let normalized_names = names
764            .iter()
765            .map(|name| {
766                if name.contains("_") {
767                    name.replace("_", "").to_ascii_lowercase()
768                } else {
769                    name.to_ascii_lowercase()
770                }
771            })
772            .collect::<Vec<String>>();
773        let names_search_tree = stringdex_internals::tree::encode_search_tree_ukkonen(
774            normalized_names.iter().map(|name| name.as_bytes()),
775        );
776        let dir_path = doc_root.join(format!("search.index/"));
777        let _ = std::fs::remove_dir_all(&dir_path); // if already missing, no problem
778        stringdex_internals::write_tree_to_disk(
779            &names_search_tree,
780            &dir_path,
781            &mut serialized_root,
782        )
783        .map_err(|error| Error {
784            file: dir_path,
785            error: format!("failed to write name tree to disk: {error}"),
786        })?;
787        std::mem::drop(names_search_tree);
788        serialized_root.extend_from_slice(br#"","#);
789        serialized_root.extend_from_slice(&perform_write_strings(
790            doc_root,
791            "normalizedName",
792            normalized_names.into_iter(),
793        )?);
794        serialized_root.extend_from_slice(br#"},"crateNames":{"#);
795        let mut crates: Vec<&[u8]> = entry_data
796            .iter()
797            .filter_map(|entry_data| Some(names[entry_data.as_ref()?.krate].as_bytes()))
798            .collect();
799        crates.sort();
800        crates.dedup();
801        serialized_root.extend_from_slice(&perform_write_strings(
802            doc_root,
803            "crateNames",
804            crates.into_iter(),
805        )?);
806        serialized_root.extend_from_slice(br#"},"name":{"#);
807        serialized_root.extend_from_slice(&perform_write_strings(doc_root, "name", names.iter())?);
808        serialized_root.extend_from_slice(br#"},"path":{"#);
809        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "path", path_data)?);
810        serialized_root.extend_from_slice(br#"},"entry":{"#);
811        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "entry", entry_data)?);
812        serialized_root.extend_from_slice(br#"},"desc":{"#);
813        serialized_root.extend_from_slice(&perform_write_strings(
814            doc_root,
815            "desc",
816            descs.into_iter(),
817        )?);
818        serialized_root.extend_from_slice(br#"},"function":{"#);
819        serialized_root.extend_from_slice(&perform_write_serde(
820            doc_root,
821            "function",
822            function_data,
823        )?);
824        serialized_root.extend_from_slice(br#"},"type":{"#);
825        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "type", type_data)?);
826        serialized_root.extend_from_slice(br#"},"alias":{"#);
827        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "alias", alias_pointers)?);
828        serialized_root.extend_from_slice(br#"},"generic_inverted_index":{"#);
829        serialized_root.extend_from_slice(&perform_write_postings(
830            doc_root,
831            "generic_inverted_index",
832            generic_inverted_index,
833        )?);
834        serialized_root.extend_from_slice(br#"}}')"#);
835        fn perform_write_strings(
836            doc_root: &Path,
837            dirname: &str,
838            mut column: impl Iterator<Item = impl AsRef<[u8]> + Clone> + ExactSizeIterator,
839        ) -> Result<Vec<u8>, Error> {
840            let dir_path = doc_root.join(format!("search.index/{dirname}"));
841            stringdex_internals::write_data_to_disk(&mut column, &dir_path).map_err(|error| Error {
842                file: dir_path,
843                error: format!("failed to write column to disk: {error}"),
844            })
845        }
846        fn perform_write_serde(
847            doc_root: &Path,
848            dirname: &str,
849            column: Vec<Option<impl Serialize>>,
850        ) -> Result<Vec<u8>, Error> {
851            perform_write_strings(
852                doc_root,
853                dirname,
854                column.into_iter().map(|value| {
855                    if let Some(value) = value {
856                        serde_json::to_vec(&value).unwrap()
857                    } else {
858                        Vec::new()
859                    }
860                }),
861            )
862        }
863        fn perform_write_postings(
864            doc_root: &Path,
865            dirname: &str,
866            column: Vec<Vec<Vec<u32>>>,
867        ) -> Result<Vec<u8>, Error> {
868            perform_write_strings(
869                doc_root,
870                dirname,
871                column.into_iter().map(|postings| {
872                    let mut buf = Vec::new();
873                    encode::write_postings_to_string(&postings, &mut buf);
874                    buf
875                }),
876            )
877        }
878        std::fs::write(
879            doc_root.join(format!("search.index/root{resource_suffix}.js")),
880            serialized_root,
881        )
882        .map_err(|error| Error {
883            file: doc_root.join(format!("search.index/root{resource_suffix}.js")),
884            error: format!("failed to write root to disk: {error}"),
885        })?;
886        Ok(())
887    }
888}
889
890#[derive(Clone, Debug)]
891struct EntryData {
892    krate: usize,
893    ty: ItemType,
894    module_path: Option<usize>,
895    exact_module_path: Option<usize>,
896    parent: Option<usize>,
897    trait_parent: Option<usize>,
898    deprecated: bool,
899    associated_item_disambiguator: Option<String>,
900}
901
902impl Serialize for EntryData {
903    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
904    where
905        S: Serializer,
906    {
907        let mut seq = serializer.serialize_seq(None)?;
908        seq.serialize_element(&self.krate)?;
909        seq.serialize_element(&self.ty)?;
910        seq.serialize_element(&self.module_path.map(|id| id + 1).unwrap_or(0))?;
911        seq.serialize_element(&self.exact_module_path.map(|id| id + 1).unwrap_or(0))?;
912        seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?;
913        seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?;
914        seq.serialize_element(&if self.deprecated { 1 } else { 0 })?;
915        if let Some(disambig) = &self.associated_item_disambiguator {
916            seq.serialize_element(&disambig)?;
917        }
918        seq.end()
919    }
920}
921
922impl<'de> Deserialize<'de> for EntryData {
923    fn deserialize<D>(deserializer: D) -> Result<EntryData, D::Error>
924    where
925        D: Deserializer<'de>,
926    {
927        struct EntryDataVisitor;
928        impl<'de> de::Visitor<'de> for EntryDataVisitor {
929            type Value = EntryData;
930            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
931                write!(formatter, "path data")
932            }
933            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<EntryData, A::Error> {
934                let krate: usize =
935                    v.next_element()?.ok_or_else(|| A::Error::missing_field("krate"))?;
936                let ty: ItemType =
937                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
938                let module_path: SerializedOptional32 =
939                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
940                let exact_module_path: SerializedOptional32 = v
941                    .next_element()?
942                    .ok_or_else(|| A::Error::missing_field("exact_module_path"))?;
943                let parent: SerializedOptional32 =
944                    v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?;
945                let trait_parent: SerializedOptional32 =
946                    v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?;
947
948                let deprecated: u32 = v.next_element()?.unwrap_or(0);
949                let associated_item_disambiguator: Option<String> = v.next_element()?;
950                Ok(EntryData {
951                    krate,
952                    ty,
953                    module_path: Option::<i32>::from(module_path).map(|path| path as usize),
954                    exact_module_path: Option::<i32>::from(exact_module_path)
955                        .map(|path| path as usize),
956                    parent: Option::<i32>::from(parent).map(|path| path as usize),
957                    trait_parent: Option::<i32>::from(trait_parent).map(|path| path as usize),
958                    deprecated: deprecated != 0,
959                    associated_item_disambiguator,
960                })
961            }
962        }
963        deserializer.deserialize_any(EntryDataVisitor)
964    }
965}
966
967#[derive(Clone, Debug)]
968struct PathData {
969    ty: ItemType,
970    module_path: Vec<Symbol>,
971    exact_module_path: Option<Vec<Symbol>>,
972}
973
974impl Serialize for PathData {
975    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
976    where
977        S: Serializer,
978    {
979        let mut seq = serializer.serialize_seq(None)?;
980        seq.serialize_element(&self.ty)?;
981        seq.serialize_element(&if self.module_path.is_empty() {
982            String::new()
983        } else {
984            join_path_syms(&self.module_path)
985        })?;
986        if let Some(ref path) = self.exact_module_path {
987            seq.serialize_element(&if path.is_empty() {
988                String::new()
989            } else {
990                join_path_syms(path)
991            })?;
992        }
993        seq.end()
994    }
995}
996
997impl<'de> Deserialize<'de> for PathData {
998    fn deserialize<D>(deserializer: D) -> Result<PathData, D::Error>
999    where
1000        D: Deserializer<'de>,
1001    {
1002        struct PathDataVisitor;
1003        impl<'de> de::Visitor<'de> for PathDataVisitor {
1004            type Value = PathData;
1005            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1006                write!(formatter, "path data")
1007            }
1008            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<PathData, A::Error> {
1009                let ty: ItemType =
1010                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
1011                let module_path: String =
1012                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
1013                let exact_module_path: Option<String> =
1014                    v.next_element()?.and_then(SerializedOptionalString::into);
1015                Ok(PathData {
1016                    ty,
1017                    module_path: if module_path.is_empty() {
1018                        vec![]
1019                    } else {
1020                        module_path.split("::").map(Symbol::intern).collect()
1021                    },
1022                    exact_module_path: exact_module_path.map(|path| {
1023                        if path.is_empty() {
1024                            vec![]
1025                        } else {
1026                            path.split("::").map(Symbol::intern).collect()
1027                        }
1028                    }),
1029                })
1030            }
1031        }
1032        deserializer.deserialize_any(PathDataVisitor)
1033    }
1034}
1035
1036#[derive(Clone, Debug)]
1037struct TypeData {
1038    /// If set to "true", the generics can be matched without having to
1039    /// mention the type itself. The truth table, assuming `Unboxable`
1040    /// has `search_unbox = true` and `Inner` has `search_unbox = false`
1041    ///
1042    /// | **query**          | `Unboxable<Inner>` | `Inner` | `Inner<Unboxable>` |
1043    /// |--------------------|--------------------|---------|--------------------|
1044    /// | `Inner`            | yes                | yes     | yes                |
1045    /// | `Unboxable`        | yes                | no      | no                 |
1046    /// | `Unboxable<Inner>` | yes                | no      | no                 |
1047    /// | `Inner<Unboxable>` | no                 | no      | yes                |
1048    search_unbox: bool,
1049    /// List of functions that mention this type in their type signature,
1050    /// on the left side of the `->` arrow.
1051    ///
1052    /// - The outer layer is sorted by number of types that appear in the
1053    ///   type signature. The search engine iterates over these in order from
1054    ///   smallest to largest. Functions with less stuff in their type
1055    ///   signature are more likely to be what the user wants, because we never
1056    ///   show functions that are *missing* parts of the query, so removing..
1057    ///
1058    /// - The inner layer is the list of functions.
1059    inverted_function_inputs_index: Vec<Vec<u32>>,
1060    /// List of functions that mention this type in their type signature,
1061    /// on the right side of the `->` arrow.
1062    inverted_function_output_index: Vec<Vec<u32>>,
1063}
1064
1065impl Serialize for TypeData {
1066    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1067    where
1068        S: Serializer,
1069    {
1070        let mut seq = serializer.serialize_seq(None)?;
1071        let mut buf = Vec::new();
1072        encode::write_postings_to_string(&self.inverted_function_inputs_index, &mut buf);
1073        let mut serialized_result = Vec::new();
1074        stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result).unwrap();
1075        seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?;
1076        buf.clear();
1077        serialized_result.clear();
1078        encode::write_postings_to_string(&self.inverted_function_output_index, &mut buf);
1079        stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result).unwrap();
1080        seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?;
1081        if self.search_unbox {
1082            seq.serialize_element(&1)?;
1083        }
1084        seq.end()
1085    }
1086}
1087
1088impl<'de> Deserialize<'de> for TypeData {
1089    fn deserialize<D>(deserializer: D) -> Result<TypeData, D::Error>
1090    where
1091        D: Deserializer<'de>,
1092    {
1093        struct TypeDataVisitor;
1094        impl<'de> de::Visitor<'de> for TypeDataVisitor {
1095            type Value = TypeData;
1096            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1097                write!(formatter, "type data")
1098            }
1099            fn visit_none<E>(self) -> Result<TypeData, E> {
1100                Ok(TypeData {
1101                    inverted_function_inputs_index: vec![],
1102                    inverted_function_output_index: vec![],
1103                    search_unbox: false,
1104                })
1105            }
1106            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<TypeData, A::Error> {
1107                let inverted_function_inputs_index: String =
1108                    v.next_element()?.unwrap_or(String::new());
1109                let inverted_function_output_index: String =
1110                    v.next_element()?.unwrap_or(String::new());
1111                let search_unbox: u32 = v.next_element()?.unwrap_or(0);
1112                let mut idx: Vec<u8> = Vec::new();
1113                stringdex_internals::decode::read_base64_from_bytes(
1114                    inverted_function_inputs_index.as_bytes(),
1115                    &mut idx,
1116                )
1117                .unwrap();
1118                let mut inverted_function_inputs_index = Vec::new();
1119                encode::read_postings_from_string(&mut inverted_function_inputs_index, &idx);
1120                idx.clear();
1121                stringdex_internals::decode::read_base64_from_bytes(
1122                    inverted_function_output_index.as_bytes(),
1123                    &mut idx,
1124                )
1125                .unwrap();
1126                let mut inverted_function_output_index = Vec::new();
1127                encode::read_postings_from_string(&mut inverted_function_output_index, &idx);
1128                Ok(TypeData {
1129                    inverted_function_inputs_index,
1130                    inverted_function_output_index,
1131                    search_unbox: search_unbox == 1,
1132                })
1133            }
1134        }
1135        deserializer.deserialize_any(TypeDataVisitor)
1136    }
1137}
1138
1139enum SerializedOptionalString {
1140    None,
1141    Some(String),
1142}
1143
1144impl From<SerializedOptionalString> for Option<String> {
1145    fn from(me: SerializedOptionalString) -> Option<String> {
1146        match me {
1147            SerializedOptionalString::Some(string) => Some(string),
1148            SerializedOptionalString::None => None,
1149        }
1150    }
1151}
1152
1153impl Serialize for SerializedOptionalString {
1154    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1155    where
1156        S: Serializer,
1157    {
1158        match self {
1159            SerializedOptionalString::Some(string) => string.serialize(serializer),
1160            SerializedOptionalString::None => 0.serialize(serializer),
1161        }
1162    }
1163}
1164impl<'de> Deserialize<'de> for SerializedOptionalString {
1165    fn deserialize<D>(deserializer: D) -> Result<SerializedOptionalString, D::Error>
1166    where
1167        D: Deserializer<'de>,
1168    {
1169        struct SerializedOptionalStringVisitor;
1170        impl<'de> de::Visitor<'de> for SerializedOptionalStringVisitor {
1171            type Value = SerializedOptionalString;
1172            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1173                write!(formatter, "0 or string")
1174            }
1175            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptionalString, E> {
1176                if v != 0 {
1177                    return Err(E::missing_field("not 0"));
1178                }
1179                Ok(SerializedOptionalString::None)
1180            }
1181            fn visit_string<E: de::Error>(self, v: String) -> Result<SerializedOptionalString, E> {
1182                Ok(SerializedOptionalString::Some(v))
1183            }
1184            fn visit_str<E: de::Error>(self, v: &str) -> Result<SerializedOptionalString, E> {
1185                Ok(SerializedOptionalString::Some(v.to_string()))
1186            }
1187        }
1188        deserializer.deserialize_any(SerializedOptionalStringVisitor)
1189    }
1190}
1191
1192enum SerializedOptional32 {
1193    None,
1194    Some(i32),
1195}
1196
1197impl From<SerializedOptional32> for Option<i32> {
1198    fn from(me: SerializedOptional32) -> Option<i32> {
1199        match me {
1200            SerializedOptional32::Some(number) => Some(number),
1201            SerializedOptional32::None => None,
1202        }
1203    }
1204}
1205
1206impl Serialize for SerializedOptional32 {
1207    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1208    where
1209        S: Serializer,
1210    {
1211        match self {
1212            &SerializedOptional32::Some(number) if number < 0 => number.serialize(serializer),
1213            &SerializedOptional32::Some(number) => (number + 1).serialize(serializer),
1214            &SerializedOptional32::None => 0.serialize(serializer),
1215        }
1216    }
1217}
1218impl<'de> Deserialize<'de> for SerializedOptional32 {
1219    fn deserialize<D>(deserializer: D) -> Result<SerializedOptional32, D::Error>
1220    where
1221        D: Deserializer<'de>,
1222    {
1223        struct SerializedOptional32Visitor;
1224        impl<'de> de::Visitor<'de> for SerializedOptional32Visitor {
1225            type Value = SerializedOptional32;
1226            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1227                write!(formatter, "integer")
1228            }
1229            fn visit_i64<E: de::Error>(self, v: i64) -> Result<SerializedOptional32, E> {
1230                Ok(match v {
1231                    0 => SerializedOptional32::None,
1232                    v if v < 0 => SerializedOptional32::Some(v as i32),
1233                    v => SerializedOptional32::Some(v as i32 - 1),
1234                })
1235            }
1236            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptional32, E> {
1237                Ok(match v {
1238                    0 => SerializedOptional32::None,
1239                    v => SerializedOptional32::Some(v as i32 - 1),
1240                })
1241            }
1242        }
1243        deserializer.deserialize_any(SerializedOptional32Visitor)
1244    }
1245}
1246
1247/// Builds the search index from the collected metadata
1248pub(crate) fn build_index(
1249    krate: &clean::Crate,
1250    cache: &mut Cache,
1251    tcx: TyCtxt<'_>,
1252    doc_root: &Path,
1253    resource_suffix: &str,
1254    should_merge: &ShouldMerge,
1255) -> Result<SerializedSearchIndex, Error> {
1256    let mut search_index = std::mem::take(&mut cache.search_index);
1257
1258    // Attach all orphan items to the type's definition if the type
1259    // has since been learned.
1260    for &OrphanImplItem { impl_id, parent, trait_parent, ref item, ref impl_generics } in
1261        &cache.orphan_impl_items
1262    {
1263        if let Some((fqp, _)) = cache.paths.get(&parent) {
1264            let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
1265            search_index.push(IndexItem {
1266                ty: item.type_(),
1267                defid: item.item_id.as_def_id(),
1268                name: item.name.unwrap(),
1269                module_path: fqp[..fqp.len() - 1].to_vec(),
1270                desc,
1271                parent: Some(parent),
1272                parent_idx: None,
1273                trait_parent,
1274                trait_parent_idx: None,
1275                exact_module_path: None,
1276                impl_id,
1277                search_type: get_function_type_for_search(
1278                    item,
1279                    tcx,
1280                    impl_generics.as_ref(),
1281                    Some(parent),
1282                    cache,
1283                ),
1284                aliases: item.attrs.get_doc_aliases(),
1285                deprecation: item.deprecation(tcx),
1286            });
1287        }
1288    }
1289
1290    // Sort search index items. This improves the compressibility of the search index.
1291    search_index.sort_unstable_by(|k1, k2| {
1292        // `sort_unstable_by_key` produces lifetime errors
1293        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
1294        let k1 =
1295            (&k1.module_path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate)));
1296        let k2 =
1297            (&k2.module_path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate)));
1298        Ord::cmp(&k1, &k2)
1299    });
1300
1301    // Now, convert to an on-disk search index format
1302    //
1303    // if there's already a search index, load it into memory and add the new entries to it
1304    // otherwise, do nothing
1305    let mut serialized_index = if should_merge.read_rendered_cci {
1306        SerializedSearchIndex::load(doc_root, resource_suffix)?
1307    } else {
1308        SerializedSearchIndex::default()
1309    };
1310
1311    // The crate always goes first in this list
1312    let crate_name = krate.name(tcx);
1313    let crate_doc =
1314        short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache));
1315    let crate_idx = {
1316        let crate_path = (ItemType::ExternCrate, vec![crate_name]);
1317        match serialized_index.crate_paths_index.entry(crate_path) {
1318            Entry::Occupied(index) => {
1319                let index = *index.get();
1320                serialized_index.descs[index] = crate_doc;
1321                for type_data in serialized_index.type_data.iter_mut() {
1322                    if let Some(TypeData {
1323                        inverted_function_inputs_index,
1324                        inverted_function_output_index,
1325                        ..
1326                    }) = type_data
1327                    {
1328                        for list in inverted_function_inputs_index
1329                            .iter_mut()
1330                            .chain(inverted_function_output_index.iter_mut())
1331                        {
1332                            list.retain(|fnid| {
1333                                serialized_index.entry_data[usize::try_from(*fnid).unwrap()]
1334                                    .as_ref()
1335                                    .unwrap()
1336                                    .krate
1337                                    != index
1338                            });
1339                        }
1340                    }
1341                }
1342                for i in (index + 1)..serialized_index.entry_data.len() {
1343                    // if this crate has been built before, replace its stuff with new
1344                    if let Some(EntryData { krate, .. }) = serialized_index.entry_data[i]
1345                        && krate == index
1346                    {
1347                        serialized_index.entry_data[i] = None;
1348                        serialized_index.descs[i] = String::new();
1349                        serialized_index.function_data[i] = None;
1350                        if serialized_index.path_data[i].is_none() {
1351                            serialized_index.names[i] = String::new();
1352                        }
1353                    }
1354                    if let Some(alias_pointer) = serialized_index.alias_pointers[i]
1355                        && serialized_index.entry_data[alias_pointer].is_none()
1356                    {
1357                        serialized_index.alias_pointers[i] = None;
1358                        if serialized_index.path_data[i].is_none()
1359                            && serialized_index.entry_data[i].is_none()
1360                        {
1361                            serialized_index.names[i] = String::new();
1362                        }
1363                    }
1364                }
1365                index
1366            }
1367            Entry::Vacant(slot) => {
1368                let krate = serialized_index.names.len();
1369                slot.insert(krate);
1370                serialized_index.push(
1371                    crate_name.as_str().to_string(),
1372                    Some(PathData {
1373                        ty: ItemType::ExternCrate,
1374                        module_path: vec![],
1375                        exact_module_path: None,
1376                    }),
1377                    Some(EntryData {
1378                        krate,
1379                        ty: ItemType::ExternCrate,
1380                        module_path: None,
1381                        exact_module_path: None,
1382                        parent: None,
1383                        trait_parent: None,
1384                        deprecated: false,
1385                        associated_item_disambiguator: None,
1386                    }),
1387                    crate_doc,
1388                    None,
1389                    None,
1390                    None,
1391                );
1392                krate
1393            }
1394        }
1395    };
1396
1397    // First, populate associated item parents and trait parents
1398    let crate_items: Vec<&mut IndexItem> = search_index
1399        .iter_mut()
1400        .map(|item| {
1401            let mut defid_to_rowid = |defid, check_external: bool| {
1402                cache
1403                    .paths
1404                    .get(&defid)
1405                    .or_else(|| check_external.then(|| cache.external_paths.get(&defid)).flatten())
1406                    .map(|&(ref fqp, ty)| {
1407                        let pathid = serialized_index.names.len();
1408                        match serialized_index.crate_paths_index.entry((ty, fqp.clone())) {
1409                            Entry::Occupied(entry) => *entry.get(),
1410                            Entry::Vacant(entry) => {
1411                                entry.insert(pathid);
1412                                let (name, path) = fqp.split_last().unwrap();
1413                                serialized_index.push_path(
1414                                    name.as_str().to_string(),
1415                                    PathData {
1416                                        ty,
1417                                        module_path: path.to_vec(),
1418                                        exact_module_path: if let Some(exact_path) =
1419                                            cache.exact_paths.get(&defid)
1420                                            && let Some((name2, exact_path)) =
1421                                                exact_path.split_last()
1422                                            && name == name2
1423                                        {
1424                                            Some(exact_path.to_vec())
1425                                        } else {
1426                                            None
1427                                        },
1428                                    },
1429                                );
1430                                usize::try_from(pathid).unwrap()
1431                            }
1432                        }
1433                    })
1434            };
1435            item.parent_idx = item.parent.and_then(|p| defid_to_rowid(p, false));
1436            item.trait_parent_idx = item.trait_parent.and_then(|p| defid_to_rowid(p, true));
1437
1438            if let Some(defid) = item.defid
1439                && item.parent_idx.is_none()
1440            {
1441                // If this is a re-export, retain the original path.
1442                // Associated items don't use this.
1443                // Their parent carries the exact fqp instead.
1444                let exact_fqp = cache
1445                    .exact_paths
1446                    .get(&defid)
1447                    .or_else(|| cache.external_paths.get(&defid).map(|(fqp, _)| fqp));
1448                item.exact_module_path = exact_fqp.and_then(|fqp| {
1449                    // Re-exports only count if the name is exactly the same.
1450                    // This is a size optimization, since it means we only need
1451                    // to store the name once (and the path is re-used for everything
1452                    // exported from this same module). It's also likely to Do
1453                    // What I Mean, since if a re-export changes the name, it might
1454                    // also be a change in semantic meaning.
1455                    if fqp.last() != Some(&item.name) {
1456                        return None;
1457                    }
1458                    let path = if item.ty == ItemType::Macro
1459                        && find_attr!(tcx.get_all_attrs(defid), AttributeKind::MacroExport { .. })
1460                    {
1461                        // `#[macro_export]` always exports to the crate root.
1462                        vec![tcx.crate_name(defid.krate)]
1463                    } else {
1464                        if fqp.len() < 2 {
1465                            return None;
1466                        }
1467                        fqp[..fqp.len() - 1].to_vec()
1468                    };
1469                    if path == item.module_path {
1470                        return None;
1471                    }
1472                    Some(path)
1473                });
1474            } else if let Some(parent_idx) = item.parent_idx {
1475                let i = usize::try_from(parent_idx).unwrap();
1476                item.module_path =
1477                    serialized_index.path_data[i].as_ref().unwrap().module_path.clone();
1478                item.exact_module_path =
1479                    serialized_index.path_data[i].as_ref().unwrap().exact_module_path.clone();
1480            }
1481
1482            &mut *item
1483        })
1484        .collect();
1485
1486    // Now, find anywhere that the same name is used for two different items
1487    // these need a disambiguator hash for lints
1488    let mut associated_item_duplicates = FxHashMap::<(usize, ItemType, Symbol), usize>::default();
1489    for item in crate_items.iter().map(|x| &*x) {
1490        if item.impl_id.is_some()
1491            && let Some(parent_idx) = item.parent_idx
1492        {
1493            let count =
1494                associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
1495            *count += 1;
1496        }
1497    }
1498
1499    // now populate the actual entries, type data, and function data
1500    for item in crate_items {
1501        assert_eq!(
1502            item.parent.is_some(),
1503            item.parent_idx.is_some(),
1504            "`{}` is missing idx",
1505            item.name
1506        );
1507
1508        let module_path = Some(serialized_index.get_id_by_module_path(&item.module_path));
1509        let exact_module_path = item
1510            .exact_module_path
1511            .as_ref()
1512            .map(|path| serialized_index.get_id_by_module_path(path));
1513
1514        let new_entry_id = serialized_index.add_entry(
1515            item.name,
1516            EntryData {
1517                ty: item.ty,
1518                parent: item.parent_idx,
1519                trait_parent: item.trait_parent_idx,
1520                module_path,
1521                exact_module_path,
1522                deprecated: item.deprecation.is_some(),
1523                associated_item_disambiguator: if let Some(impl_id) = item.impl_id
1524                    && let Some(parent_idx) = item.parent_idx
1525                    && associated_item_duplicates
1526                        .get(&(parent_idx, item.ty, item.name))
1527                        .copied()
1528                        .unwrap_or(0)
1529                        > 1
1530                {
1531                    Some(render::get_id_for_impl(tcx, ItemId::DefId(impl_id)))
1532                } else {
1533                    None
1534                },
1535                krate: crate_idx,
1536            },
1537            item.desc.to_string(),
1538        );
1539
1540        // Aliases
1541        // -------
1542        for alias in &item.aliases[..] {
1543            serialized_index.push_alias(alias.as_str().to_string(), new_entry_id);
1544        }
1545
1546        // Function signature reverse index
1547        // --------------------------------
1548        fn insert_into_map(
1549            ty: ItemType,
1550            path: &[Symbol],
1551            exact_path: Option<&[Symbol]>,
1552            search_unbox: bool,
1553            serialized_index: &mut SerializedSearchIndex,
1554            used_in_function_signature: &mut BTreeSet<isize>,
1555        ) -> RenderTypeId {
1556            let pathid = serialized_index.names.len();
1557            let pathid = match serialized_index.crate_paths_index.entry((ty, path.to_vec())) {
1558                Entry::Occupied(entry) => {
1559                    let id = *entry.get();
1560                    if serialized_index.type_data[id].as_mut().is_none() {
1561                        serialized_index.type_data[id] = Some(TypeData {
1562                            search_unbox,
1563                            inverted_function_inputs_index: Vec::new(),
1564                            inverted_function_output_index: Vec::new(),
1565                        });
1566                    } else if search_unbox {
1567                        serialized_index.type_data[id].as_mut().unwrap().search_unbox = true;
1568                    }
1569                    id
1570                }
1571                Entry::Vacant(entry) => {
1572                    entry.insert(pathid);
1573                    let (name, path) = path.split_last().unwrap();
1574                    serialized_index.push_type(
1575                        name.to_string(),
1576                        PathData {
1577                            ty,
1578                            module_path: path.to_vec(),
1579                            exact_module_path: if let Some(exact_path) = exact_path
1580                                && let Some((name2, exact_path)) = exact_path.split_last()
1581                                && name == name2
1582                            {
1583                                Some(exact_path.to_vec())
1584                            } else {
1585                                None
1586                            },
1587                        },
1588                        TypeData {
1589                            inverted_function_inputs_index: Vec::new(),
1590                            inverted_function_output_index: Vec::new(),
1591                            search_unbox,
1592                        },
1593                    );
1594                    pathid
1595                }
1596            };
1597            used_in_function_signature.insert(isize::try_from(pathid).unwrap());
1598            RenderTypeId::Index(isize::try_from(pathid).unwrap())
1599        }
1600
1601        fn convert_render_type_id(
1602            id: RenderTypeId,
1603            cache: &mut Cache,
1604            serialized_index: &mut SerializedSearchIndex,
1605            used_in_function_signature: &mut BTreeSet<isize>,
1606            tcx: TyCtxt<'_>,
1607        ) -> Option<RenderTypeId> {
1608            use crate::clean::PrimitiveType;
1609            let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
1610            let search_unbox = match id {
1611                RenderTypeId::Mut => false,
1612                RenderTypeId::DefId(defid) => {
1613                    utils::has_doc_flag(tcx, defid, |d| d.search_unbox.is_some())
1614                }
1615                RenderTypeId::Primitive(
1616                    PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple,
1617                ) => true,
1618                RenderTypeId::Primitive(..) => false,
1619                RenderTypeId::AssociatedType(..) => false,
1620                // this bool is only used by `insert_into_map`, so it doesn't matter what we set here
1621                // because Index means we've already inserted into the map
1622                RenderTypeId::Index(_) => false,
1623            };
1624            match id {
1625                RenderTypeId::Mut => Some(insert_into_map(
1626                    ItemType::Keyword,
1627                    &[kw::Mut],
1628                    None,
1629                    search_unbox,
1630                    serialized_index,
1631                    used_in_function_signature,
1632                )),
1633                RenderTypeId::DefId(defid) => {
1634                    if let Some(&(ref fqp, item_type)) =
1635                        paths.get(&defid).or_else(|| external_paths.get(&defid))
1636                    {
1637                        if tcx.lang_items().fn_mut_trait() == Some(defid)
1638                            || tcx.lang_items().fn_once_trait() == Some(defid)
1639                            || tcx.lang_items().fn_trait() == Some(defid)
1640                        {
1641                            let name = *fqp.last().unwrap();
1642                            // Make absolutely sure we use this single, correct path,
1643                            // because search.js needs to match. If we don't do this,
1644                            // there are three different paths that these traits may
1645                            // appear to come from.
1646                            Some(insert_into_map(
1647                                item_type,
1648                                &[sym::core, sym::ops, name],
1649                                Some(&[sym::core, sym::ops, name]),
1650                                search_unbox,
1651                                serialized_index,
1652                                used_in_function_signature,
1653                            ))
1654                        } else {
1655                            let exact_fqp = exact_paths
1656                                .get(&defid)
1657                                .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
1658                                .map(|v| &v[..])
1659                                // Re-exports only count if the name is exactly the same.
1660                                // This is a size optimization, since it means we only need
1661                                // to store the name once (and the path is re-used for everything
1662                                // exported from this same module). It's also likely to Do
1663                                // What I Mean, since if a re-export changes the name, it might
1664                                // also be a change in semantic meaning.
1665                                .filter(|this_fqp| this_fqp.last() == fqp.last());
1666                            Some(insert_into_map(
1667                                item_type,
1668                                fqp,
1669                                exact_fqp,
1670                                search_unbox,
1671                                serialized_index,
1672                                used_in_function_signature,
1673                            ))
1674                        }
1675                    } else {
1676                        None
1677                    }
1678                }
1679                RenderTypeId::Primitive(primitive) => {
1680                    let sym = primitive.as_sym();
1681                    Some(insert_into_map(
1682                        ItemType::Primitive,
1683                        &[sym],
1684                        None,
1685                        search_unbox,
1686                        serialized_index,
1687                        used_in_function_signature,
1688                    ))
1689                }
1690                RenderTypeId::Index(index) => {
1691                    used_in_function_signature.insert(index);
1692                    Some(id)
1693                }
1694                RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
1695                    ItemType::AssocType,
1696                    &[sym],
1697                    None,
1698                    search_unbox,
1699                    serialized_index,
1700                    used_in_function_signature,
1701                )),
1702            }
1703        }
1704
1705        fn convert_render_type(
1706            ty: &mut RenderType,
1707            cache: &mut Cache,
1708            serialized_index: &mut SerializedSearchIndex,
1709            used_in_function_signature: &mut BTreeSet<isize>,
1710            tcx: TyCtxt<'_>,
1711        ) {
1712            if let Some(generics) = &mut ty.generics {
1713                for item in generics {
1714                    convert_render_type(
1715                        item,
1716                        cache,
1717                        serialized_index,
1718                        used_in_function_signature,
1719                        tcx,
1720                    );
1721                }
1722            }
1723            if let Some(bindings) = &mut ty.bindings {
1724                bindings.retain_mut(|(associated_type, constraints)| {
1725                    let converted_associated_type = convert_render_type_id(
1726                        *associated_type,
1727                        cache,
1728                        serialized_index,
1729                        used_in_function_signature,
1730                        tcx,
1731                    );
1732                    let Some(converted_associated_type) = converted_associated_type else {
1733                        return false;
1734                    };
1735                    *associated_type = converted_associated_type;
1736                    for constraint in constraints {
1737                        convert_render_type(
1738                            constraint,
1739                            cache,
1740                            serialized_index,
1741                            used_in_function_signature,
1742                            tcx,
1743                        );
1744                    }
1745                    true
1746                });
1747            }
1748            let Some(id) = ty.id else {
1749                assert!(ty.generics.is_some());
1750                return;
1751            };
1752            ty.id = convert_render_type_id(
1753                id,
1754                cache,
1755                serialized_index,
1756                used_in_function_signature,
1757                tcx,
1758            );
1759            use crate::clean::PrimitiveType;
1760            // These cases are added to the inverted index, but not actually included
1761            // in the signature. There's a matching set of cases in the
1762            // `unifyFunctionTypeIsMatchCandidate` function, for the slow path.
1763            match id {
1764                // typeNameIdOfArrayOrSlice
1765                RenderTypeId::Primitive(PrimitiveType::Array | PrimitiveType::Slice) => {
1766                    insert_into_map(
1767                        ItemType::Primitive,
1768                        &[Symbol::intern("[]")],
1769                        None,
1770                        false,
1771                        serialized_index,
1772                        used_in_function_signature,
1773                    );
1774                }
1775                RenderTypeId::Primitive(PrimitiveType::Tuple | PrimitiveType::Unit) => {
1776                    // typeNameIdOfArrayOrSlice
1777                    insert_into_map(
1778                        ItemType::Primitive,
1779                        &[Symbol::intern("()")],
1780                        None,
1781                        false,
1782                        serialized_index,
1783                        used_in_function_signature,
1784                    );
1785                }
1786                // typeNameIdOfHof
1787                RenderTypeId::Primitive(PrimitiveType::Fn) => {
1788                    insert_into_map(
1789                        ItemType::Primitive,
1790                        &[Symbol::intern("->")],
1791                        None,
1792                        false,
1793                        serialized_index,
1794                        used_in_function_signature,
1795                    );
1796                }
1797                RenderTypeId::DefId(did)
1798                    if tcx.lang_items().fn_mut_trait() == Some(did)
1799                        || tcx.lang_items().fn_once_trait() == Some(did)
1800                        || tcx.lang_items().fn_trait() == Some(did) =>
1801                {
1802                    insert_into_map(
1803                        ItemType::Primitive,
1804                        &[Symbol::intern("->")],
1805                        None,
1806                        false,
1807                        serialized_index,
1808                        used_in_function_signature,
1809                    );
1810                }
1811                // not special
1812                _ => {}
1813            }
1814        }
1815        if let Some(search_type) = &mut item.search_type {
1816            let mut used_in_function_inputs = BTreeSet::new();
1817            let mut used_in_function_output = BTreeSet::new();
1818            for item in &mut search_type.inputs {
1819                convert_render_type(
1820                    item,
1821                    cache,
1822                    &mut serialized_index,
1823                    &mut used_in_function_inputs,
1824                    tcx,
1825                );
1826            }
1827            for item in &mut search_type.output {
1828                convert_render_type(
1829                    item,
1830                    cache,
1831                    &mut serialized_index,
1832                    &mut used_in_function_output,
1833                    tcx,
1834                );
1835            }
1836            let used_in_constraints = search_type
1837                .where_clause
1838                .iter_mut()
1839                .map(|constraint| {
1840                    let mut used_in_constraint = BTreeSet::new();
1841                    for trait_ in constraint {
1842                        convert_render_type(
1843                            trait_,
1844                            cache,
1845                            &mut serialized_index,
1846                            &mut used_in_constraint,
1847                            tcx,
1848                        );
1849                    }
1850                    used_in_constraint
1851                })
1852                .collect::<Vec<_>>();
1853            loop {
1854                let mut inserted_any = false;
1855                for (i, used_in_constraint) in used_in_constraints.iter().enumerate() {
1856                    let id = !(i as isize);
1857                    if used_in_function_inputs.contains(&id)
1858                        && !used_in_function_inputs.is_superset(&used_in_constraint)
1859                    {
1860                        used_in_function_inputs.extend(used_in_constraint.iter().copied());
1861                        inserted_any = true;
1862                    }
1863                    if used_in_function_output.contains(&id)
1864                        && !used_in_function_output.is_superset(&used_in_constraint)
1865                    {
1866                        used_in_function_output.extend(used_in_constraint.iter().copied());
1867                        inserted_any = true;
1868                    }
1869                }
1870                if !inserted_any {
1871                    break;
1872                }
1873            }
1874            let search_type_size = search_type.size() +
1875                // Artificially give struct fields a size of 8 instead of their real
1876                // size of 2. This is because search.js sorts them to the end, so
1877                // by pushing them down, we prevent them from blocking real 2-arity functions.
1878                //
1879                // The number 8 is arbitrary. We want it big, but not enormous,
1880                // because the postings list has to fill in an empty array for each
1881                // unoccupied size.
1882                if item.ty.is_fn_like() { 0 } else { 16 };
1883            serialized_index.function_data[new_entry_id] = Some(search_type.clone());
1884
1885            #[derive(Clone, Copy)]
1886            enum InvertedIndexType {
1887                Inputs,
1888                Output,
1889            }
1890            impl InvertedIndexType {
1891                fn from_type_data(self, type_data: &mut TypeData) -> &mut Vec<Vec<u32>> {
1892                    match self {
1893                        Self::Inputs => &mut type_data.inverted_function_inputs_index,
1894                        Self::Output => &mut type_data.inverted_function_output_index,
1895                    }
1896                }
1897            }
1898
1899            let mut process_used_in_function =
1900                |used_in_function: BTreeSet<isize>, index_type: InvertedIndexType| {
1901                    for index in used_in_function {
1902                        let postings = if index >= 0 {
1903                            assert!(serialized_index.path_data[index as usize].is_some());
1904                            index_type.from_type_data(
1905                                serialized_index.type_data[index as usize].as_mut().unwrap(),
1906                            )
1907                        } else {
1908                            let generic_id = index.unsigned_abs() - 1;
1909                            if generic_id >= serialized_index.generic_inverted_index.len() {
1910                                serialized_index
1911                                    .generic_inverted_index
1912                                    .resize(generic_id + 1, Vec::new());
1913                            }
1914                            &mut serialized_index.generic_inverted_index[generic_id]
1915                        };
1916                        if search_type_size >= postings.len() {
1917                            postings.resize(search_type_size + 1, Vec::new());
1918                        }
1919                        let posting = &mut postings[search_type_size];
1920                        if posting.last() != Some(&(new_entry_id as u32)) {
1921                            posting.push(new_entry_id as u32);
1922                        }
1923                    }
1924                };
1925
1926            process_used_in_function(used_in_function_inputs, InvertedIndexType::Inputs);
1927            process_used_in_function(used_in_function_output, InvertedIndexType::Output);
1928        }
1929    }
1930
1931    Ok(serialized_index.sort())
1932}
1933
1934pub(crate) fn get_function_type_for_search(
1935    item: &clean::Item,
1936    tcx: TyCtxt<'_>,
1937    impl_generics: Option<&(clean::Type, clean::Generics)>,
1938    parent: Option<DefId>,
1939    cache: &Cache,
1940) -> Option<IndexItemFunctionType> {
1941    let mut trait_info = None;
1942    let impl_or_trait_generics = impl_generics.or_else(|| {
1943        if let Some(def_id) = parent
1944            && let Some(trait_) = cache.traits.get(&def_id)
1945            && let Some((path, _)) =
1946                cache.paths.get(&def_id).or_else(|| cache.external_paths.get(&def_id))
1947        {
1948            let path = clean::Path {
1949                res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, def_id),
1950                segments: path
1951                    .iter()
1952                    .map(|name| clean::PathSegment {
1953                        name: *name,
1954                        args: clean::GenericArgs::AngleBracketed {
1955                            args: ThinVec::new(),
1956                            constraints: ThinVec::new(),
1957                        },
1958                    })
1959                    .collect(),
1960            };
1961            trait_info = Some((clean::Type::Path { path }, trait_.generics.clone()));
1962            Some(trait_info.as_ref().unwrap())
1963        } else {
1964            None
1965        }
1966    });
1967    let (mut inputs, mut output, param_names, where_clause) = match item.kind {
1968        clean::ForeignFunctionItem(ref f, _)
1969        | clean::FunctionItem(ref f)
1970        | clean::MethodItem(ref f, _)
1971        | clean::RequiredMethodItem(ref f) => {
1972            get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
1973        }
1974        clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
1975        clean::StaticItem(ref s) => make_nullary_fn(&s.type_),
1976        clean::StructFieldItem(ref t) if let Some(parent) = parent => {
1977            let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> =
1978                Default::default();
1979            let output = get_index_type(t, vec![], &mut rgen);
1980            let input = RenderType {
1981                id: Some(RenderTypeId::DefId(parent)),
1982                generics: None,
1983                bindings: None,
1984            };
1985            (vec![input], vec![output], vec![], vec![])
1986        }
1987        _ => return None,
1988    };
1989
1990    inputs.retain(|a| a.id.is_some() || a.generics.is_some());
1991    output.retain(|a| a.id.is_some() || a.generics.is_some());
1992
1993    Some(IndexItemFunctionType { inputs, output, where_clause, param_names })
1994}
1995
1996fn get_index_type(
1997    clean_type: &clean::Type,
1998    generics: Vec<RenderType>,
1999    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2000) -> RenderType {
2001    RenderType {
2002        id: get_index_type_id(clean_type, rgen),
2003        generics: if generics.is_empty() { None } else { Some(generics) },
2004        bindings: None,
2005    }
2006}
2007
2008fn get_index_type_id(
2009    clean_type: &clean::Type,
2010    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2011) -> Option<RenderTypeId> {
2012    use rustc_hir::def::{DefKind, Res};
2013    match *clean_type {
2014        clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
2015        clean::DynTrait(ref bounds, _) => {
2016            bounds.first().map(|b| RenderTypeId::DefId(b.trait_.def_id()))
2017        }
2018        clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
2019        clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)),
2020        clean::RawPointer { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)),
2021        // The type parameters are converted to generics in `simplify_fn_type`
2022        clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
2023        clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
2024        clean::BareFunction(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Fn)),
2025        clean::Tuple(ref n) if n.is_empty() => {
2026            Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit))
2027        }
2028        clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
2029        clean::QPath(ref data) => {
2030            if data.self_type.is_self_type()
2031                && let Some(clean::Path { res: Res::Def(DefKind::Trait, trait_), .. }) = data.trait_
2032            {
2033                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2034                let (idx, _) = rgen
2035                    .entry(SimplifiedParam::AssociatedType(trait_, data.assoc.name))
2036                    .or_insert_with(|| (idx, Vec::new()));
2037                Some(RenderTypeId::Index(*idx))
2038            } else {
2039                None
2040            }
2041        }
2042        // Not supported yet
2043        clean::Type::Pat(..)
2044        | clean::Generic(_)
2045        | clean::SelfTy
2046        | clean::ImplTrait(_)
2047        | clean::Infer
2048        | clean::UnsafeBinder(_) => None,
2049    }
2050}
2051
2052#[derive(Clone, Copy, Eq, Hash, PartialEq)]
2053enum SimplifiedParam {
2054    // other kinds of type parameters are identified by their name
2055    Symbol(Symbol),
2056    // every argument-position impl trait is its own type parameter
2057    Anonymous(isize),
2058    // in a trait definition, the associated types are all bound to
2059    // their own type parameter
2060    AssociatedType(DefId, Symbol),
2061}
2062
2063/// The point of this function is to lower generics and types into the simplified form that the
2064/// frontend search engine can use.
2065///
2066/// For example, `[T, U, i32]]` where you have the bounds: `T: Display, U: Option<T>` will return
2067/// `[-1, -2, i32] where -1: Display, -2: Option<-1>`. If a type parameter has no trait bound, it
2068/// will still get a number. If a constraint is present but not used in the actual types, it will
2069/// not be added to the map.
2070///
2071/// This function also works recursively.
2072#[instrument(level = "trace", skip(tcx, rgen, cache))]
2073fn simplify_fn_type<'a, 'tcx>(
2074    self_: Option<&'a Type>,
2075    generics: &Generics,
2076    arg: &'a Type,
2077    tcx: TyCtxt<'tcx>,
2078    recurse: usize,
2079    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2080    is_return: bool,
2081    cache: &Cache,
2082) -> Option<RenderType> {
2083    if recurse >= 10 {
2084        // FIXME: remove this whole recurse thing when the recursion bug is fixed
2085        // See #59502 for the original issue.
2086        return None;
2087    }
2088
2089    // First, check if it's "Self".
2090    let (is_self, arg) = if let Some(self_) = self_
2091        && arg.is_self_type()
2092    {
2093        (true, self_)
2094    } else {
2095        (false, arg)
2096    };
2097
2098    // If this argument is a type parameter and not a trait bound or a type, we need to look
2099    // for its bounds.
2100    match *arg {
2101        Type::Generic(arg_s) => {
2102            // First we check if the bounds are in a `where` predicate...
2103            let where_bounds = generics
2104                .where_predicates
2105                .iter()
2106                .filter_map(|g| {
2107                    if let WherePredicate::BoundPredicate { ty, bounds, .. } = g
2108                        && *ty == *arg
2109                    {
2110                        Some(bounds)
2111                    } else {
2112                        None
2113                    }
2114                })
2115                .flatten();
2116            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
2117            let inline_bounds = generics
2118                .params
2119                .iter()
2120                .find(|g| g.is_type() && g.name == arg_s)
2121                .and_then(|bound| bound.get_bounds())
2122                .into_iter()
2123                .flatten();
2124
2125            let type_bounds = where_bounds
2126                .chain(inline_bounds)
2127                .filter_map(
2128                    |bound| if let Some(path) = bound.get_trait_path() { Some(path) } else { None },
2129                )
2130                .filter_map(|path| {
2131                    let ty = Type::Path { path };
2132                    simplify_fn_type(self_, generics, &ty, tcx, recurse + 1, rgen, is_return, cache)
2133                })
2134                .collect();
2135
2136            Some(if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
2137                RenderType { id: Some(RenderTypeId::Index(*idx)), generics: None, bindings: None }
2138            } else {
2139                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2140                rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
2141                RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
2142            })
2143        }
2144        Type::ImplTrait(ref bounds) => {
2145            let type_bounds = bounds
2146                .iter()
2147                .filter_map(|bound| bound.get_trait_path())
2148                .filter_map(|path| {
2149                    let ty = Type::Path { path };
2150                    simplify_fn_type(self_, generics, &ty, tcx, recurse + 1, rgen, is_return, cache)
2151                })
2152                .collect::<Vec<_>>();
2153            Some(if is_return && !type_bounds.is_empty() {
2154                // In return position, `impl Trait` is a unique thing.
2155                RenderType { id: None, generics: Some(type_bounds), bindings: None }
2156            } else {
2157                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
2158                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2159                rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
2160                RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
2161            })
2162        }
2163        Type::Slice(ref ty) => {
2164            let ty_generics =
2165                simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2166                    .into_iter()
2167                    .collect();
2168            Some(get_index_type(arg, ty_generics, rgen))
2169        }
2170        Type::Array(ref ty, _) => {
2171            let ty_generics =
2172                simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2173                    .into_iter()
2174                    .collect();
2175            Some(get_index_type(arg, ty_generics, rgen))
2176        }
2177        Type::Tuple(ref tys) => {
2178            let ty_generics = tys
2179                .iter()
2180                .filter_map(|ty| {
2181                    simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2182                })
2183                .collect();
2184            Some(get_index_type(arg, ty_generics, rgen))
2185        }
2186        Type::BareFunction(ref bf) => {
2187            let ty_generics = bf
2188                .decl
2189                .inputs
2190                .iter()
2191                .map(|arg| &arg.type_)
2192                .filter_map(|ty| {
2193                    simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2194                })
2195                .collect();
2196            // The search index, for simplicity's sake, represents fn pointers and closures
2197            // the same way: as a tuple for the parameters, and an associated type for the
2198            // return type.
2199            let ty_output = simplify_fn_type(
2200                self_,
2201                generics,
2202                &bf.decl.output,
2203                tcx,
2204                recurse + 1,
2205                rgen,
2206                is_return,
2207                cache,
2208            )
2209            .into_iter()
2210            .collect();
2211            let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
2212            Some(RenderType {
2213                id: get_index_type_id(arg, rgen),
2214                bindings: Some(ty_bindings),
2215                generics: Some(ty_generics),
2216            })
2217        }
2218        Type::BorrowedRef { lifetime: _, mutability, ref type_ }
2219        | Type::RawPointer(mutability, ref type_) => {
2220            let mut ty_generics = Vec::new();
2221            if mutability.is_mut() {
2222                ty_generics.push(RenderType {
2223                    id: Some(RenderTypeId::Mut),
2224                    generics: None,
2225                    bindings: None,
2226                });
2227            }
2228            if let Some(ty) =
2229                simplify_fn_type(self_, generics, type_, tcx, recurse + 1, rgen, is_return, cache)
2230            {
2231                ty_generics.push(ty);
2232            }
2233            Some(get_index_type(arg, ty_generics, rgen))
2234        }
2235        _ => {
2236            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
2237            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
2238            //
2239            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
2240            // we will look for them but not for `T`).
2241            let mut ty_generics = Vec::new();
2242            let mut ty_constraints = Vec::new();
2243            if let Some(arg_generics) = arg.generic_args() {
2244                ty_generics = arg_generics
2245                    .into_iter()
2246                    .filter_map(|param| match param {
2247                        clean::GenericArg::Type(ty) => Some(ty),
2248                        _ => None,
2249                    })
2250                    .filter_map(|ty| {
2251                        simplify_fn_type(
2252                            self_,
2253                            generics,
2254                            &ty,
2255                            tcx,
2256                            recurse + 1,
2257                            rgen,
2258                            is_return,
2259                            cache,
2260                        )
2261                    })
2262                    .collect();
2263                for constraint in arg_generics.constraints() {
2264                    simplify_fn_constraint(
2265                        self_,
2266                        generics,
2267                        &constraint,
2268                        tcx,
2269                        recurse + 1,
2270                        &mut ty_constraints,
2271                        rgen,
2272                        is_return,
2273                        cache,
2274                    );
2275                }
2276            }
2277            // Every trait associated type on self gets assigned to a type parameter index
2278            // this same one is used later for any appearances of these types
2279            //
2280            // for example, Iterator::next is:
2281            //
2282            //     trait Iterator {
2283            //         fn next(&mut self) -> Option<Self::Item>
2284            //     }
2285            //
2286            // Self is technically just Iterator, but we want to pretend it's more like this:
2287            //
2288            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
2289            if is_self
2290                && let Type::Path { path } = arg
2291                && let def_id = path.def_id()
2292                && let Some(trait_) = cache.traits.get(&def_id)
2293                && trait_.items.iter().any(|at| at.is_required_associated_type())
2294            {
2295                for assoc_ty in &trait_.items {
2296                    if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) =
2297                        &assoc_ty.kind
2298                        && let Some(name) = assoc_ty.name
2299                    {
2300                        let idx = -isize::try_from(rgen.len() + 1).unwrap();
2301                        let (idx, stored_bounds) = rgen
2302                            .entry(SimplifiedParam::AssociatedType(def_id, name))
2303                            .or_insert_with(|| (idx, Vec::new()));
2304                        let idx = *idx;
2305                        if stored_bounds.is_empty() {
2306                            // Can't just pass stored_bounds to simplify_fn_type,
2307                            // because it also accepts rgen as a parameter.
2308                            // Instead, have it fill in this local, then copy it into the map afterward.
2309                            let type_bounds = bounds
2310                                .iter()
2311                                .filter_map(|bound| bound.get_trait_path())
2312                                .filter_map(|path| {
2313                                    let ty = Type::Path { path };
2314                                    simplify_fn_type(
2315                                        self_,
2316                                        generics,
2317                                        &ty,
2318                                        tcx,
2319                                        recurse + 1,
2320                                        rgen,
2321                                        is_return,
2322                                        cache,
2323                                    )
2324                                })
2325                                .collect();
2326                            let stored_bounds = &mut rgen
2327                                .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
2328                                .unwrap()
2329                                .1;
2330                            if stored_bounds.is_empty() {
2331                                *stored_bounds = type_bounds;
2332                            }
2333                        }
2334                        ty_constraints.push((
2335                            RenderTypeId::AssociatedType(name),
2336                            vec![RenderType {
2337                                id: Some(RenderTypeId::Index(idx)),
2338                                generics: None,
2339                                bindings: None,
2340                            }],
2341                        ))
2342                    }
2343                }
2344            }
2345            let id = get_index_type_id(arg, rgen);
2346            if id.is_some() || !ty_generics.is_empty() {
2347                Some(RenderType {
2348                    id,
2349                    bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
2350                    generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
2351                })
2352            } else {
2353                None
2354            }
2355        }
2356    }
2357}
2358
2359fn simplify_fn_constraint<'a>(
2360    self_: Option<&'a Type>,
2361    generics: &Generics,
2362    constraint: &'a clean::AssocItemConstraint,
2363    tcx: TyCtxt<'_>,
2364    recurse: usize,
2365    res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
2366    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2367    is_return: bool,
2368    cache: &Cache,
2369) {
2370    let mut ty_constraints = Vec::new();
2371    let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name);
2372    for param in &constraint.assoc.args {
2373        match param {
2374            clean::GenericArg::Type(arg) => {
2375                ty_constraints.extend(simplify_fn_type(
2376                    self_,
2377                    generics,
2378                    &arg,
2379                    tcx,
2380                    recurse + 1,
2381                    rgen,
2382                    is_return,
2383                    cache,
2384                ));
2385            }
2386            clean::GenericArg::Lifetime(_)
2387            | clean::GenericArg::Const(_)
2388            | clean::GenericArg::Infer => {}
2389        }
2390    }
2391    for constraint in constraint.assoc.args.constraints() {
2392        simplify_fn_constraint(
2393            self_,
2394            generics,
2395            &constraint,
2396            tcx,
2397            recurse + 1,
2398            res,
2399            rgen,
2400            is_return,
2401            cache,
2402        );
2403    }
2404    match &constraint.kind {
2405        clean::AssocItemConstraintKind::Equality { term } => {
2406            if let clean::Term::Type(arg) = &term {
2407                ty_constraints.extend(simplify_fn_type(
2408                    self_,
2409                    generics,
2410                    arg,
2411                    tcx,
2412                    recurse + 1,
2413                    rgen,
2414                    is_return,
2415                    cache,
2416                ));
2417            }
2418        }
2419        clean::AssocItemConstraintKind::Bound { bounds } => {
2420            for bound in &bounds[..] {
2421                if let Some(path) = bound.get_trait_path() {
2422                    let ty = Type::Path { path };
2423                    ty_constraints.extend(simplify_fn_type(
2424                        self_,
2425                        generics,
2426                        &ty,
2427                        tcx,
2428                        recurse + 1,
2429                        rgen,
2430                        is_return,
2431                        cache,
2432                    ));
2433                }
2434            }
2435        }
2436    }
2437    res.push((ty_constrained_assoc, ty_constraints));
2438}
2439
2440/// Create a fake nullary function.
2441///
2442/// Used to allow type-based search on constants and statics.
2443fn make_nullary_fn(
2444    clean_type: &clean::Type,
2445) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
2446    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
2447    let output = get_index_type(clean_type, vec![], &mut rgen);
2448    (vec![], vec![output], vec![], vec![])
2449}
2450
2451/// Return the full list of types when bounds have been resolved.
2452///
2453/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
2454/// `[u32, Display, Option]`.
2455fn get_fn_inputs_and_outputs(
2456    func: &Function,
2457    tcx: TyCtxt<'_>,
2458    impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
2459    cache: &Cache,
2460) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
2461    let decl = &func.decl;
2462
2463    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
2464
2465    let combined_generics;
2466    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
2467        match (impl_generics.is_empty(), func.generics.is_empty()) {
2468            (true, _) => (Some(impl_self), &func.generics),
2469            (_, true) => (Some(impl_self), impl_generics),
2470            (false, false) => {
2471                let params =
2472                    func.generics.params.iter().chain(&impl_generics.params).cloned().collect();
2473                let where_predicates = func
2474                    .generics
2475                    .where_predicates
2476                    .iter()
2477                    .chain(&impl_generics.where_predicates)
2478                    .cloned()
2479                    .collect();
2480                combined_generics = clean::Generics { params, where_predicates };
2481                (Some(impl_self), &combined_generics)
2482            }
2483        }
2484    } else {
2485        (None, &func.generics)
2486    };
2487
2488    let param_types = decl
2489        .inputs
2490        .iter()
2491        .filter_map(|param| {
2492            simplify_fn_type(self_, generics, &param.type_, tcx, 0, &mut rgen, false, cache)
2493        })
2494        .collect();
2495
2496    let ret_types = simplify_fn_type(self_, generics, &decl.output, tcx, 0, &mut rgen, true, cache)
2497        .into_iter()
2498        .collect();
2499
2500    let mut simplified_params = rgen.into_iter().collect::<Vec<_>>();
2501    simplified_params.sort_by_key(|(_, (idx, _))| -idx);
2502    (
2503        param_types,
2504        ret_types,
2505        simplified_params
2506            .iter()
2507            .map(|(name, (_idx, _traits))| match name {
2508                SimplifiedParam::Symbol(name) => Some(*name),
2509                SimplifiedParam::Anonymous(_) => None,
2510                SimplifiedParam::AssociatedType(def_id, name) => {
2511                    Some(Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)))
2512                }
2513            })
2514            .collect(),
2515        simplified_params.into_iter().map(|(_name, (_idx, traits))| traits).collect(),
2516    )
2517}