From a755d8d3328af84894e8e49cb56ea5abc26f9bb3 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sun, 23 Feb 2020 02:38:33 +0100
Subject: [PATCH 1/5] Support type search for arguments and returned types

---
 src/librustdoc/clean/mod.rs                |  20 ++++
 src/librustdoc/clean/types.rs              |  14 +--
 src/librustdoc/clean/utils.rs              |  40 +++++--
 src/librustdoc/html/render.rs              |  69 +++++++++--
 src/librustdoc/html/render/cache.rs        |  47 +++++---
 src/librustdoc/html/static/main.js         | 128 +++++++++++----------
 src/test/rustdoc-js-std/return-specific.js |   7 ++
 7 files changed, 222 insertions(+), 103 deletions(-)
 create mode 100644 src/test/rustdoc-js-std/return-specific.js

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7c845a9b66bbd..16a73ad8d36ad 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1078,6 +1078,26 @@ impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
     }
 }
 
+impl Clean<TypeKind> for hir::def::DefKind {
+    fn clean(&self, _: &DocContext<'_>) -> TypeKind {
+        match *self {
+            hir::def::DefKind::Mod => TypeKind::Module,
+            hir::def::DefKind::Struct => TypeKind::Struct,
+            hir::def::DefKind::Union => TypeKind::Union,
+            hir::def::DefKind::Enum => TypeKind::Enum,
+            hir::def::DefKind::Trait => TypeKind::Trait,
+            hir::def::DefKind::TyAlias => TypeKind::Typedef,
+            hir::def::DefKind::ForeignTy => TypeKind::Foreign,
+            hir::def::DefKind::TraitAlias => TypeKind::TraitAlias,
+            hir::def::DefKind::Fn => TypeKind::Function,
+            hir::def::DefKind::Const => TypeKind::Const,
+            hir::def::DefKind::Static => TypeKind::Static,
+            hir::def::DefKind::Macro(_) => TypeKind::Macro,
+            _ => TypeKind::Foreign,
+        }
+    }
+}
+
 impl Clean<Item> for hir::TraitItem<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
         let inner = match self.kind {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 9c3bedfe37c7a..6ee6a52c46757 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -836,8 +836,8 @@ pub struct Method {
     pub decl: FnDecl,
     pub header: hir::FnHeader,
     pub defaultness: Option<hir::Defaultness>,
-    pub all_types: Vec<Type>,
-    pub ret_types: Vec<Type>,
+    pub all_types: Vec<(Type, TypeKind)>,
+    pub ret_types: Vec<(Type, TypeKind)>,
 }
 
 #[derive(Clone, Debug)]
@@ -845,8 +845,8 @@ pub struct TyMethod {
     pub header: hir::FnHeader,
     pub decl: FnDecl,
     pub generics: Generics,
-    pub all_types: Vec<Type>,
-    pub ret_types: Vec<Type>,
+    pub all_types: Vec<(Type, TypeKind)>,
+    pub ret_types: Vec<(Type, TypeKind)>,
 }
 
 #[derive(Clone, Debug)]
@@ -854,8 +854,8 @@ pub struct Function {
     pub decl: FnDecl,
     pub generics: Generics,
     pub header: hir::FnHeader,
-    pub all_types: Vec<Type>,
-    pub ret_types: Vec<Type>,
+    pub all_types: Vec<(Type, TypeKind)>,
+    pub ret_types: Vec<(Type, TypeKind)>,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -1043,7 +1043,7 @@ pub enum PrimitiveType {
     Never,
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
 pub enum TypeKind {
     Enum,
     Function,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 99e3d731d0d6f..e4808a9090967 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -186,7 +186,7 @@ pub fn get_real_types(
     arg: &Type,
     cx: &DocContext<'_>,
     recurse: i32,
-) -> FxHashSet<Type> {
+) -> FxHashSet<(Type, TypeKind)> {
     let arg_s = arg.print().to_string();
     let mut res = FxHashSet::default();
     if recurse >= 10 {
@@ -211,7 +211,11 @@ pub fn get_real_types(
                                 if !adds.is_empty() {
                                     res.extend(adds);
                                 } else if !ty.is_full_generic() {
-                                    res.insert(ty);
+                                    if let Some(did) = ty.def_id() {
+                                        if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+                                            res.insert((ty, kind));
+                                        }
+                                    }
                                 }
                             }
                         }
@@ -227,13 +231,21 @@ pub fn get_real_types(
                     if !adds.is_empty() {
                         res.extend(adds);
                     } else if !ty.is_full_generic() {
-                        res.insert(ty.clone());
+                        if let Some(did) = ty.def_id() {
+                            if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+                                res.insert((ty.clone(), kind));
+                            }
+                        }
                     }
                 }
             }
         }
     } else {
-        res.insert(arg.clone());
+        if let Some(did) = arg.def_id() {
+            if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+                res.insert((arg.clone(), kind));
+            }
+        }
         if let Some(gens) = arg.generics() {
             for gen in gens.iter() {
                 if gen.is_full_generic() {
@@ -241,8 +253,10 @@ pub fn get_real_types(
                     if !adds.is_empty() {
                         res.extend(adds);
                     }
-                } else {
-                    res.insert(gen.clone());
+                } else if let Some(did) = gen.def_id() {
+                    if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+                        res.insert((gen.clone(), kind));
+                    }
                 }
             }
         }
@@ -258,7 +272,7 @@ pub fn get_all_types(
     generics: &Generics,
     decl: &FnDecl,
     cx: &DocContext<'_>,
-) -> (Vec<Type>, Vec<Type>) {
+) -> (Vec<(Type, TypeKind)>, Vec<(Type, TypeKind)>) {
     let mut all_types = FxHashSet::default();
     for arg in decl.inputs.values.iter() {
         if arg.type_.is_self_type() {
@@ -268,7 +282,11 @@ pub fn get_all_types(
         if !args.is_empty() {
             all_types.extend(args);
         } else {
-            all_types.insert(arg.type_.clone());
+            if let Some(did) = arg.type_.def_id() {
+                if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+                    all_types.insert((arg.type_.clone(), kind));
+                }
+            }
         }
     }
 
@@ -276,7 +294,11 @@ pub fn get_all_types(
         FnRetTy::Return(ref return_type) => {
             let mut ret = get_real_types(generics, &return_type, cx, 0);
             if ret.is_empty() {
-                ret.insert(return_type.clone());
+                if let Some(did) = return_type.def_id() {
+                    if let Some(kind) = cx.tcx.def_kind(did).clean(cx) {
+                        ret.insert((return_type.clone(), kind));
+                    }
+                }
             }
             ret.into_iter().collect()
         }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 4dd2a6562a4cd..79c2adc4c213f 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -59,7 +59,7 @@ use rustc_span::symbol::{sym, Symbol};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
-use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy};
+use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind};
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, ErrorStorage, PathError};
 use crate::doctree;
@@ -303,8 +303,10 @@ impl Serialize for IndexItem {
 /// A type used for the search index.
 #[derive(Debug)]
 struct Type {
+    ty: Option<DefId>,
+    idx: Option<usize>,
     name: Option<String>,
-    generics: Option<Vec<String>>,
+    generics: Option<Vec<Generic>>,
 }
 
 impl Serialize for Type {
@@ -314,7 +316,11 @@ impl Serialize for Type {
     {
         if let Some(name) = &self.name {
             let mut seq = serializer.serialize_seq(None)?;
-            seq.serialize_element(&name)?;
+            if let Some(id) = self.idx {
+                seq.serialize_element(&id)?;
+            } else {
+                seq.serialize_element(&name)?;
+            }
             if let Some(generics) = &self.generics {
                 seq.serialize_element(&generics)?;
             }
@@ -325,11 +331,32 @@ impl Serialize for Type {
     }
 }
 
+/// A type used for the search index.
+#[derive(Debug)]
+struct Generic {
+    name: String,
+    defid: Option<DefId>,
+    idx: Option<usize>,
+}
+
+impl Serialize for Generic {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        if let Some(id) = self.idx {
+            serializer.serialize_some(&id)
+        } else {
+            serializer.serialize_some(&self.name)
+        }
+    }
+}
+
 /// Full type of functions/methods in the search index.
 #[derive(Debug)]
 struct IndexItemFunctionType {
-    inputs: Vec<Type>,
-    output: Option<Vec<Type>>,
+    inputs: Vec<TypeWithKind>,
+    output: Option<Vec<TypeWithKind>>,
 }
 
 impl Serialize for IndexItemFunctionType {
@@ -340,8 +367,8 @@ impl Serialize for IndexItemFunctionType {
         // If we couldn't figure out a type, just write `null`.
         let mut iter = self.inputs.iter();
         if match self.output {
-            Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()),
-            None => iter.any(|ref i| i.name.is_none()),
+            Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
+            None => iter.any(|ref i| i.ty.name.is_none()),
         } {
             serializer.serialize_none()
         } else {
@@ -359,6 +386,34 @@ impl Serialize for IndexItemFunctionType {
     }
 }
 
+#[derive(Debug)]
+pub struct TypeWithKind {
+    ty: Type,
+    kind: TypeKind,
+}
+
+impl From<(Type, TypeKind)> for TypeWithKind {
+    fn from(x: (Type, TypeKind)) -> TypeWithKind {
+        TypeWithKind {
+            ty: x.0,
+            kind: x.1,
+        }
+    }
+}
+
+impl Serialize for TypeWithKind {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let mut seq = serializer.serialize_seq(None)?;
+        seq.serialize_element(&self.ty.name)?;
+        let x: ItemType = self.kind.into();
+        seq.serialize_element(&x)?;
+        seq.end()
+    }
+}
+
 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
 thread_local!(pub static CURRENT_DEPTH: Cell<usize> = Cell::new(0));
 
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index a0a35e4ce4b85..9dae5c1b05495 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -12,7 +12,7 @@ use std::path::{Path, PathBuf};
 use serde::Serialize;
 
 use super::{plain_summary_line, shorten, Impl, IndexItem, IndexItemFunctionType, ItemType};
-use super::{RenderInfo, Type};
+use super::{Generic, RenderInfo, Type, TypeWithKind};
 
 /// Indicates where an external crate can be found.
 pub enum ExternalLocation {
@@ -587,19 +587,22 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     let mut lastpathid = 0usize;
 
     for item in search_index {
-        item.parent_idx = item.parent.map(|defid| {
-            if defid_to_pathid.contains_key(&defid) {
-                *defid_to_pathid.get(&defid).expect("no pathid")
-            } else {
-                let pathid = lastpathid;
-                defid_to_pathid.insert(defid, pathid);
-                lastpathid += 1;
+        item.parent_idx = item.parent.and_then(|defid| {
+        if defid_to_pathid.contains_key(&defid) {
+            defid_to_pathid.get(&defid).map(|x| *x)
+        } else {
+            let pathid = lastpathid;
+            defid_to_pathid.insert(defid, pathid);
+            lastpathid += 1;
 
-                let &(ref fqp, short) = paths.get(&defid).unwrap();
+            if let Some(&(ref fqp, short)) = paths.get(&defid) {
                 crate_paths.push((short, fqp.last().unwrap().clone()));
-                pathid
+                Some(pathid)
+            } else {
+                None
             }
-        });
+        }
+    });
 
         // Omit the parent path if it is same to that of the prior item.
         if lastpath == item.path {
@@ -646,12 +649,15 @@ fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
         _ => return None,
     };
 
-    let inputs =
-        all_types.iter().map(|arg| get_index_type(&arg)).filter(|a| a.name.is_some()).collect();
+    let inputs = all_types
+        .iter()
+        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+        .filter(|a| a.ty.name.is_some())
+        .collect();
     let output = ret_types
         .iter()
-        .map(|arg| get_index_type(&arg))
-        .filter(|a| a.name.is_some())
+        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+        .filter(|a| a.ty.name.is_some())
         .collect::<Vec<_>>();
     let output = if output.is_empty() { None } else { Some(output) };
 
@@ -660,6 +666,8 @@ fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
 
 fn get_index_type(clean_type: &clean::Type) -> Type {
     let t = Type {
+        ty: clean_type.def_id(),
+        idx: None,
         name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
         generics: get_generics(clean_type),
     };
@@ -684,12 +692,15 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
     }
 }
 
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
+fn get_generics(clean_type: &clean::Type) -> Option<Vec<Generic>> {
     clean_type.generics().and_then(|types| {
         let r = types
             .iter()
-            .filter_map(|t| get_index_type_name(t, false))
-            .map(|s| s.to_ascii_lowercase())
+            .filter_map(|t| if let Some(name) = get_index_type_name(t, false) {
+                Some(Generic { name: name.to_ascii_lowercase(), defid: t.def_id(), idx: None })
+            } else {
+                None
+            })
             .collect::<Vec<_>>();
         if r.is_empty() { None } else { Some(r) }
     })
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 2870c6e0a6147..735044af5afc0 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -526,13 +526,14 @@ function getSearchElement() {
     }
 
     function initSearch(rawSearchIndex) {
-        var currentResults, index, searchIndex;
         var MAX_LEV_DISTANCE = 3;
         var MAX_RESULTS = 200;
         var GENERICS_DATA = 1;
         var NAME = 0;
         var INPUTS_DATA = 0;
         var OUTPUT_DATA = 1;
+        var NO_TYPE_FILTER = -1;
+        var currentResults, index, searchIndex;
         var params = getQueryStringParams();
 
         // Populate search bar with query string search term when provided,
@@ -559,7 +560,7 @@ function getSearchElement() {
                         return i;
                     }
                 }
-                return -1;
+                return NO_TYPE_FILTER;
             }
 
             var valLower = query.query.toLowerCase(),
@@ -722,6 +723,13 @@ function getSearchElement() {
                 };
             }
 
+            function getObjectFromId(id) {
+                if (typeof id === "number") {
+                    return searchIndex[id];
+                }
+                return {'name': id};
+            }
+
             function checkGenerics(obj, val) {
                 // The names match, but we need to be sure that all generics kinda
                 // match as well.
@@ -738,8 +746,10 @@ function getSearchElement() {
                         for (var y = 0; y < vlength; ++y) {
                             var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
                             var elength = elems.length;
+                            var firstGeneric = getObjectFromId(val.generics[y]).name;
                             for (var x = 0; x < elength; ++x) {
-                                var tmp_lev = levenshtein(elems[x], val.generics[y]);
+                                var tmp_lev = levenshtein(getObjectFromId(elems[x]).name,
+                                                          firstGeneric);
                                 if (tmp_lev < lev.lev) {
                                     lev.lev = tmp_lev;
                                     lev.pos = x;
@@ -774,8 +784,9 @@ function getSearchElement() {
 
                                 for (var y = 0; allFound === true && y < val.generics.length; ++y) {
                                     allFound = false;
+                                    var firstGeneric = getObjectFromId(val.generics[y]).name;
                                     for (x = 0; allFound === false && x < elems.length; ++x) {
-                                        allFound = elems[x] === val.generics[y];
+                                        allFound = getObjectFromId(elems[x]).name === firstGeneric;
                                     }
                                     if (allFound === true) {
                                         elems.splice(x - 1, 1);
@@ -832,16 +843,23 @@ function getSearchElement() {
                 return lev_distance + 1;
             }
 
-            function findArg(obj, val, literalSearch) {
+            function findArg(obj, val, literalSearch, typeFilter) {
                 var lev_distance = MAX_LEV_DISTANCE + 1;
 
-                if (obj && obj.type && obj.type[INPUTS_DATA] &&
-                      obj.type[INPUTS_DATA].length > 0) {
+                if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
                     var length = obj.type[INPUTS_DATA].length;
                     for (var i = 0; i < length; i++) {
-                        var tmp = checkType(obj.type[INPUTS_DATA][i], val, literalSearch);
-                        if (literalSearch === true && tmp === true) {
-                            return true;
+                        var tmp = obj.type[INPUTS_DATA][i];
+                        if (typePassesFilter(typeFilter, tmp[1]) === false) {
+                            continue;
+                        }
+                        tmp[0] = tmp[NAME];
+                        var tmp = checkType(tmp, val, literalSearch);
+                        if (literalSearch === true) {
+                            if (tmp === true) {
+                                return true;
+                            }
+                            continue;
                         }
                         lev_distance = Math.min(tmp, lev_distance);
                         if (lev_distance === 0) {
@@ -852,19 +870,20 @@ function getSearchElement() {
                 return literalSearch === true ? false : lev_distance;
             }
 
-            function checkReturned(obj, val, literalSearch) {
+            function checkReturned(obj, val, literalSearch, typeFilter) {
                 var lev_distance = MAX_LEV_DISTANCE + 1;
 
                 if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
                     var ret = obj.type[OUTPUT_DATA];
-                    if (!obj.type[OUTPUT_DATA].length) {
+                    if (typeof ret[0] === "string") {
                         ret = [ret];
                     }
                     for (var x = 0; x < ret.length; ++x) {
                         var r = ret[x];
-                        if (typeof r === "string") {
-                            r = [r];
+                        if (typePassesFilter(typeFilter, r[1]) === false) {
+                            continue;
                         }
+                        r[0] = r[NAME];
                         var tmp = checkType(r, val, literalSearch);
                         if (literalSearch === true) {
                             if (tmp === true) {
@@ -920,7 +939,7 @@ function getSearchElement() {
 
             function typePassesFilter(filter, type) {
                 // No filter
-                if (filter < 0) return true;
+                if (filter <= NO_TYPE_FILTER) return true;
 
                 // Exact match
                 if (filter === type) return true;
@@ -929,11 +948,13 @@ function getSearchElement() {
                 var name = itemTypes[type];
                 switch (itemTypes[filter]) {
                     case "constant":
-                        return (name == "associatedconstant");
+                        return name === "associatedconstant";
                     case "fn":
-                        return (name == "method" || name == "tymethod");
+                        return name === "method" || name === "tymethod";
                     case "type":
-                        return (name == "primitive" || name == "keyword");
+                        return name === "primitive" || name === "associatedtype";
+                    case "trait":
+                        return name === "traitalias";
                 }
 
                 // No match
@@ -962,42 +983,33 @@ function getSearchElement() {
                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
                         continue;
                     }
-                    in_args = findArg(searchIndex[i], val, true);
-                    returned = checkReturned(searchIndex[i], val, true);
+                    in_args = findArg(searchIndex[i], val, true, typeFilter);
+                    returned = checkReturned(searchIndex[i], val, true, typeFilter);
                     ty = searchIndex[i];
                     fullId = generateId(ty);
 
-                    if (searchWords[i] === val.name) {
-                        // filter type: ... queries
-                        if (typePassesFilter(typeFilter, searchIndex[i].ty) &&
-                            results[fullId] === undefined)
-                        {
-                            results[fullId] = {id: i, index: -1};
-                        }
-                    } else if ((in_args === true || returned === true) &&
-                               typePassesFilter(typeFilter, searchIndex[i].ty)) {
-                        if (in_args === true || returned === true) {
-                            if (in_args === true) {
-                                results_in_args[fullId] = {
-                                    id: i,
-                                    index: -1,
-                                    dontValidate: true,
-                                };
-                            }
-                            if (returned === true) {
-                                results_returned[fullId] = {
-                                    id: i,
-                                    index: -1,
-                                    dontValidate: true,
-                                };
-                            }
-                        } else {
-                            results[fullId] = {
-                                id: i,
-                                index: -1,
-                                dontValidate: true,
-                            };
-                        }
+                    if (searchWords[i] === val.name
+                        && typePassesFilter(typeFilter, searchIndex[i].ty)
+                        && results[fullId] === undefined) {
+                        results[fullId] = {
+                            id: i,
+                            index: -1,
+                            dontValidate: true,
+                        };
+                    }
+                    if (in_args === true && results_in_args[fullId] === undefined) {
+                        results_in_args[fullId] = {
+                            id: i,
+                            index: -1,
+                            dontValidate: true,
+                        };
+                    }
+                    if (returned === true && results_returned[fullId] === undefined) {
+                        results_returned[fullId] = {
+                            id: i,
+                            index: -1,
+                            dontValidate: true,
+                        };
                     }
                 }
                 query.inputs = [val];
@@ -1028,7 +1040,7 @@ function getSearchElement() {
 
                     // allow searching for void (no output) functions as well
                     var typeOutput = type.length > OUTPUT_DATA ? type[OUTPUT_DATA].name : "";
-                    returned = checkReturned(ty, output, true);
+                    returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
                     if (output.name === "*" || returned === true) {
                         in_args = false;
                         var is_module = false;
@@ -1129,16 +1141,8 @@ function getSearchElement() {
                             lev += 1;
                         }
                     }
-                    if ((in_args = findArg(ty, valGenerics)) <= MAX_LEV_DISTANCE) {
-                        if (typePassesFilter(typeFilter, ty.ty) === false) {
-                            in_args = MAX_LEV_DISTANCE + 1;
-                        }
-                    }
-                    if ((returned = checkReturned(ty, valGenerics)) <= MAX_LEV_DISTANCE) {
-                        if (typePassesFilter(typeFilter, ty.ty) === false) {
-                            returned = MAX_LEV_DISTANCE + 1;
-                        }
-                    }
+                    in_args = findArg(ty, valGenerics, false, typeFilter);
+                    returned = checkReturned(ty, valGenerics, false, typeFilter);
 
                     lev += lev_add;
                     if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
diff --git a/src/test/rustdoc-js-std/return-specific.js b/src/test/rustdoc-js-std/return-specific.js
new file mode 100644
index 0000000000000..6cdeefd10caa8
--- /dev/null
+++ b/src/test/rustdoc-js-std/return-specific.js
@@ -0,0 +1,7 @@
+const QUERY = 'struct:chunksmut';
+
+const EXPECTED = {
+    'returned': [
+        { 'path': 'std::slice::chunks_mut', 'name': 'chunks_mut' },
+    ],
+};

From 612d375574de654021b50784d0a476f88f2bd44e Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sun, 23 Feb 2020 18:23:09 +0100
Subject: [PATCH 2/5] Update JS results tester

---
 src/test/rustdoc-js-std/return-specific.js | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/test/rustdoc-js-std/return-specific.js b/src/test/rustdoc-js-std/return-specific.js
index 6cdeefd10caa8..d9a910553b8de 100644
--- a/src/test/rustdoc-js-std/return-specific.js
+++ b/src/test/rustdoc-js-std/return-specific.js
@@ -1,7 +1,10 @@
-const QUERY = 'struct:chunksmut';
+const QUERY = 'struct:string';
 
 const EXPECTED = {
+    'in_args': [
+        { 'path': 'std::string::String', 'name': 'ne' },
+    ],
     'returned': [
-        { 'path': 'std::slice::chunks_mut', 'name': 'chunks_mut' },
+        { 'path': 'std::string::String', 'name': 'add' },
     ],
 };

From 5892d0d010b44a2c5815c8f5d1bead1b99608979 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sun, 23 Feb 2020 18:23:52 +0100
Subject: [PATCH 3/5] Add tests for new of variables

---
 src/test/rustdoc-js-std/return-specific-literal.js | 10 ++++++++++
 src/tools/rustdoc-js-std/tester.js                 |  5 +++--
 2 files changed, 13 insertions(+), 2 deletions(-)
 create mode 100644 src/test/rustdoc-js-std/return-specific-literal.js

diff --git a/src/test/rustdoc-js-std/return-specific-literal.js b/src/test/rustdoc-js-std/return-specific-literal.js
new file mode 100644
index 0000000000000..c7c347240b751
--- /dev/null
+++ b/src/test/rustdoc-js-std/return-specific-literal.js
@@ -0,0 +1,10 @@
+const QUERY = 'struct:"string"';
+
+const EXPECTED = {
+    'in_args': [
+        { 'path': 'std::string::String', 'name': 'ne' },
+    ],
+    'returned': [
+        { 'path': 'std::string::String', 'name': 'add' },
+    ],
+};
diff --git a/src/tools/rustdoc-js-std/tester.js b/src/tools/rustdoc-js-std/tester.js
index d5f0ab9f4292d..67640381a4c27 100644
--- a/src/tools/rustdoc-js-std/tester.js
+++ b/src/tools/rustdoc-js-std/tester.js
@@ -253,6 +253,7 @@ function main(argv) {
     }
     var toolchain = argv[2];
 
+    console.log(toolchain);
     var mainJs = readFileMatching("build/" + toolchain + "/doc/", "main", ".js");
     var ALIASES = readFileMatching("build/" + toolchain + "/doc/", "aliases", ".js");
     var searchIndex = readFileMatching("build/" + toolchain + "/doc/",
@@ -265,7 +266,7 @@ function main(argv) {
     finalJS = "";
 
     var arraysToLoad = ["itemTypes"];
-    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
+    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER",
                            "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
                            "TY_PRIMITIVE", "TY_KEYWORD",
                            "levenshtein_row2"];
@@ -338,7 +339,7 @@ function main(argv) {
             console.log("OK");
         }
     });
-    return errors;
+    return errors > 0 ? 1 : 0;
 }
 
 process.exit(main(process.argv));

From 71b9512ae34e1f3ee810fd8ea580db1167218f20 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sun, 23 Feb 2020 19:09:00 +0100
Subject: [PATCH 4/5] formatting

---
 src/librustdoc/html/render.rs       |  5 +---
 src/librustdoc/html/render/cache.rs | 36 +++++++++++++++--------------
 src/librustdoc/html/static/main.js  | 10 ++++----
 3 files changed, 24 insertions(+), 27 deletions(-)

diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 79c2adc4c213f..c18fea942e919 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -394,10 +394,7 @@ pub struct TypeWithKind {
 
 impl From<(Type, TypeKind)> for TypeWithKind {
     fn from(x: (Type, TypeKind)) -> TypeWithKind {
-        TypeWithKind {
-            ty: x.0,
-            kind: x.1,
-        }
+        TypeWithKind { ty: x.0, kind: x.1 }
     }
 }
 
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 9dae5c1b05495..bd703235f5ddb 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -588,21 +588,21 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
 
     for item in search_index {
         item.parent_idx = item.parent.and_then(|defid| {
-        if defid_to_pathid.contains_key(&defid) {
-            defid_to_pathid.get(&defid).map(|x| *x)
-        } else {
-            let pathid = lastpathid;
-            defid_to_pathid.insert(defid, pathid);
-            lastpathid += 1;
-
-            if let Some(&(ref fqp, short)) = paths.get(&defid) {
-                crate_paths.push((short, fqp.last().unwrap().clone()));
-                Some(pathid)
+            if defid_to_pathid.contains_key(&defid) {
+                defid_to_pathid.get(&defid).map(|x| *x)
             } else {
-                None
+                let pathid = lastpathid;
+                defid_to_pathid.insert(defid, pathid);
+                lastpathid += 1;
+
+                if let Some(&(ref fqp, short)) = paths.get(&defid) {
+                    crate_paths.push((short, fqp.last().unwrap().clone()));
+                    Some(pathid)
+                } else {
+                    None
+                }
             }
-        }
-    });
+        });
 
         // Omit the parent path if it is same to that of the prior item.
         if lastpath == item.path {
@@ -696,10 +696,12 @@ fn get_generics(clean_type: &clean::Type) -> Option<Vec<Generic>> {
     clean_type.generics().and_then(|types| {
         let r = types
             .iter()
-            .filter_map(|t| if let Some(name) = get_index_type_name(t, false) {
-                Some(Generic { name: name.to_ascii_lowercase(), defid: t.def_id(), idx: None })
-            } else {
-                None
+            .filter_map(|t| {
+                if let Some(name) = get_index_type_name(t, false) {
+                    Some(Generic { name: name.to_ascii_lowercase(), defid: t.def_id(), idx: None })
+                } else {
+                    None
+                }
             })
             .collect::<Vec<_>>();
         if r.is_empty() { None } else { Some(r) }
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 735044af5afc0..fdb143e18e653 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -853,8 +853,7 @@ function getSearchElement() {
                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
                             continue;
                         }
-                        tmp[0] = tmp[NAME];
-                        var tmp = checkType(tmp, val, literalSearch);
+                        tmp = checkType(tmp, val, literalSearch);
                         if (literalSearch === true) {
                             if (tmp === true) {
                                 return true;
@@ -879,12 +878,11 @@ function getSearchElement() {
                         ret = [ret];
                     }
                     for (var x = 0; x < ret.length; ++x) {
-                        var r = ret[x];
-                        if (typePassesFilter(typeFilter, r[1]) === false) {
+                        var tmp = ret[x];
+                        if (typePassesFilter(typeFilter, tmp[1]) === false) {
                             continue;
                         }
-                        r[0] = r[NAME];
-                        var tmp = checkType(r, val, literalSearch);
+                        tmp = checkType(r, val, literalSearch);
                         if (literalSearch === true) {
                             if (tmp === true) {
                                 return true;

From 6ffe9f30e6d986961a6d745206f46e36a05cd30d Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Tue, 3 Mar 2020 15:53:16 +0100
Subject: [PATCH 5/5] Rename render::Type to improve naming

---
 src/librustdoc/html/render.rs       | 10 +++++-----
 src/librustdoc/html/render/cache.rs |  6 +++---
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index c18fea942e919..e700cecd1e4e2 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -302,14 +302,14 @@ impl Serialize for IndexItem {
 
 /// A type used for the search index.
 #[derive(Debug)]
-struct Type {
+struct RenderType {
     ty: Option<DefId>,
     idx: Option<usize>,
     name: Option<String>,
     generics: Option<Vec<Generic>>,
 }
 
-impl Serialize for Type {
+impl Serialize for RenderType {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: Serializer,
@@ -388,12 +388,12 @@ impl Serialize for IndexItemFunctionType {
 
 #[derive(Debug)]
 pub struct TypeWithKind {
-    ty: Type,
+    ty: RenderType,
     kind: TypeKind,
 }
 
-impl From<(Type, TypeKind)> for TypeWithKind {
-    fn from(x: (Type, TypeKind)) -> TypeWithKind {
+impl From<(RenderType, TypeKind)> for TypeWithKind {
+    fn from(x: (RenderType, TypeKind)) -> TypeWithKind {
         TypeWithKind { ty: x.0, kind: x.1 }
     }
 }
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index bd703235f5ddb..bcc1a6bdb01dd 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -12,7 +12,7 @@ use std::path::{Path, PathBuf};
 use serde::Serialize;
 
 use super::{plain_summary_line, shorten, Impl, IndexItem, IndexItemFunctionType, ItemType};
-use super::{Generic, RenderInfo, Type, TypeWithKind};
+use super::{Generic, RenderInfo, RenderType, TypeWithKind};
 
 /// Indicates where an external crate can be found.
 pub enum ExternalLocation {
@@ -664,8 +664,8 @@ fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
     Some(IndexItemFunctionType { inputs, output })
 }
 
-fn get_index_type(clean_type: &clean::Type) -> Type {
-    let t = Type {
+fn get_index_type(clean_type: &clean::Type) -> RenderType {
+    let t = RenderType {
         ty: clean_type.def_id(),
         idx: None,
         name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),