Skip to main content

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