diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index e10c61901d05a..23bb020716dd5 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1410,6 +1410,12 @@ pub(crate) struct Generics {
     pub(crate) where_predicates: Vec<WherePredicate>,
 }
 
+impl Generics {
+    pub(crate) fn is_empty(&self) -> bool {
+        self.params.is_empty() && self.where_predicates.is_empty()
+    }
+}
+
 #[derive(Clone, Debug)]
 pub(crate) struct Function {
     pub(crate) decl: FnDecl,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 09aa042b1d02f..d7276a427c468 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -94,8 +94,7 @@ pub(crate) struct Cache {
 
     // Private fields only used when initially crawling a crate to build a cache
     stack: Vec<Symbol>,
-    parent_stack: Vec<DefId>,
-    parent_is_trait_impl: bool,
+    parent_stack: Vec<ParentStackItem>,
     stripped_mod: bool,
 
     pub(crate) search_index: Vec<IndexItem>,
@@ -105,7 +104,7 @@ pub(crate) struct Cache {
     // then the fully qualified name of the structure isn't presented in `paths`
     // yet when its implementation methods are being indexed. Caches such methods
     // and their parent id here and indexes them at the end of crate parsing.
-    pub(crate) orphan_impl_items: Vec<(DefId, clean::Item)>,
+    pub(crate) orphan_impl_items: Vec<OrphanImplItem>,
 
     // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
     // even though the trait itself is not exported. This can happen if a trait
@@ -261,7 +260,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             let (parent, is_inherent_impl_item) = match *item.kind {
                 clean::StrippedItem(..) => ((None, None), false),
                 clean::AssocConstItem(..) | clean::AssocTypeItem(..)
-                    if self.cache.parent_is_trait_impl =>
+                    if self
+                        .cache
+                        .parent_stack
+                        .last()
+                        .map_or(false, |parent| parent.is_trait_impl()) =>
                 {
                     // skip associated items in trait impls
                     ((None, None), false)
@@ -272,7 +275,14 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                 | clean::StructFieldItem(..)
                 | clean::VariantItem(..) => (
                     (
-                        Some(*self.cache.parent_stack.last().expect("parent_stack is empty")),
+                        Some(
+                            self.cache
+                                .parent_stack
+                                .last()
+                                .expect("parent_stack is empty")
+                                .item_id()
+                                .expect_def_id(),
+                        ),
                         Some(&self.cache.stack[..self.cache.stack.len() - 1]),
                     ),
                     false,
@@ -282,8 +292,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                         ((None, None), false)
                     } else {
                         let last = self.cache.parent_stack.last().expect("parent_stack is empty 2");
-                        let did = *last;
-                        let path = match self.cache.paths.get(&did) {
+                        let did = match &*last {
+                            ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache),
+                            ParentStackItem::Type(item_id) => item_id.as_def_id(),
+                        };
+                        let path = match did.and_then(|did| self.cache.paths.get(&did)) {
                             // The current stack not necessarily has correlation
                             // for where the type was defined. On the other
                             // hand, `paths` always has the right
@@ -291,7 +304,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                             Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]),
                             None => None,
                         };
-                        ((Some(*last), path), true)
+                        ((did, path), true)
                     }
                 }
                 _ => ((None, Some(&*self.cache.stack)), false),
@@ -315,7 +328,12 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                             desc,
                             parent,
                             parent_idx: None,
-                            search_type: get_function_type_for_search(&item, self.tcx, self.cache),
+                            search_type: get_function_type_for_search(
+                                &item,
+                                self.tcx,
+                                clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
+                                self.cache,
+                            ),
                             aliases: item.attrs.get_doc_aliases(),
                         });
                     }
@@ -323,7 +341,12 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                 (Some(parent), None) if is_inherent_impl_item => {
                     // We have a parent, but we don't know where they're
                     // defined yet. Wait for later to index this item.
-                    self.cache.orphan_impl_items.push((parent, item.clone()));
+                    let impl_generics = clean_impl_generics(self.cache.parent_stack.last());
+                    self.cache.orphan_impl_items.push(OrphanImplItem {
+                        parent,
+                        item: item.clone(),
+                        impl_generics,
+                    });
                 }
                 _ => {}
             }
@@ -398,51 +421,23 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             }
         }
 
-        // Maintain the parent stack
-        let orig_parent_is_trait_impl = self.cache.parent_is_trait_impl;
-        let parent_pushed = match *item.kind {
+        // Maintain the parent stack.
+        let (item, parent_pushed) = match *item.kind {
             clean::TraitItem(..)
             | clean::EnumItem(..)
             | clean::ForeignTypeItem
             | clean::StructItem(..)
             | clean::UnionItem(..)
-            | clean::VariantItem(..) => {
-                self.cache.parent_stack.push(item.item_id.expect_def_id());
-                self.cache.parent_is_trait_impl = false;
-                true
-            }
-            clean::ImplItem(ref i) => {
-                self.cache.parent_is_trait_impl = i.trait_.is_some();
-                match i.for_ {
-                    clean::Type::Path { ref path } => {
-                        self.cache.parent_stack.push(path.def_id());
-                        true
-                    }
-                    clean::DynTrait(ref bounds, _)
-                    | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
-                        self.cache.parent_stack.push(bounds[0].trait_.def_id());
-                        true
-                    }
-                    ref t => {
-                        let prim_did = t
-                            .primitive_type()
-                            .and_then(|t| self.cache.primitive_locations.get(&t).cloned());
-                        match prim_did {
-                            Some(did) => {
-                                self.cache.parent_stack.push(did);
-                                true
-                            }
-                            None => false,
-                        }
-                    }
-                }
+            | clean::VariantItem(..)
+            | clean::ImplItem(..) => {
+                self.cache.parent_stack.push(ParentStackItem::new(&item));
+                (self.fold_item_recur(item), true)
             }
-            _ => false,
+            _ => (self.fold_item_recur(item), false),
         };
 
         // Once we've recursively found all the generics, hoard off all the
         // implementations elsewhere.
-        let item = self.fold_item_recur(item);
         let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
             // Figure out the id of this impl. This may map to a
             // primitive rather than always to a struct/enum.
@@ -511,7 +506,64 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             self.cache.parent_stack.pop().expect("parent stack already empty");
         }
         self.cache.stripped_mod = orig_stripped_mod;
-        self.cache.parent_is_trait_impl = orig_parent_is_trait_impl;
         ret
     }
 }
+
+pub(crate) struct OrphanImplItem {
+    pub(crate) parent: DefId,
+    pub(crate) item: clean::Item,
+    pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>,
+}
+
+/// Information about trait and type parents is tracked while traversing the item tree to build
+/// the cache.
+///
+/// We don't just store `Item` in there, because `Item` contains the list of children being
+/// traversed and it would be wasteful to clone all that. We also need the item id, so just
+/// storing `ItemKind` won't work, either.
+enum ParentStackItem {
+    Impl {
+        for_: clean::Type,
+        trait_: Option<clean::Path>,
+        generics: clean::Generics,
+        kind: clean::ImplKind,
+        item_id: ItemId,
+    },
+    Type(ItemId),
+}
+
+impl ParentStackItem {
+    fn new(item: &clean::Item) -> Self {
+        match &*item.kind {
+            clean::ItemKind::ImplItem(clean::Impl { for_, trait_, generics, kind, .. }) => {
+                ParentStackItem::Impl {
+                    for_: for_.clone(),
+                    trait_: trait_.clone(),
+                    generics: generics.clone(),
+                    kind: kind.clone(),
+                    item_id: item.item_id,
+                }
+            }
+            _ => ParentStackItem::Type(item.item_id),
+        }
+    }
+    fn is_trait_impl(&self) -> bool {
+        matches!(self, ParentStackItem::Impl { trait_: Some(..), .. })
+    }
+    fn item_id(&self) -> ItemId {
+        match self {
+            ParentStackItem::Impl { item_id, .. } => *item_id,
+            ParentStackItem::Type(item_id) => *item_id,
+        }
+    }
+}
+
+fn clean_impl_generics(item: Option<&ParentStackItem>) -> Option<(clean::Type, clean::Generics)> {
+    if let Some(ParentStackItem::Impl { for_, generics, kind: clean::ImplKind::Normal, .. }) = item
+    {
+        Some((for_.clone(), generics.clone()))
+    } else {
+        None
+    }
+}
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 3daef3dbb7947..25c70f0808c6d 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -8,7 +8,7 @@ use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
 use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate};
-use crate::formats::cache::Cache;
+use crate::formats::cache::{Cache, OrphanImplItem};
 use crate::formats::item_type::ItemType;
 use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
@@ -25,8 +25,8 @@ pub(crate) fn build_index<'tcx>(
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
-    for &(did, ref item) in &cache.orphan_impl_items {
-        if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
+    for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
+        if let Some(&(ref fqp, _)) = cache.paths.get(&parent) {
             let desc = item
                 .doc_value()
                 .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
@@ -35,9 +35,9 @@ pub(crate) fn build_index<'tcx>(
                 name: item.name.unwrap().to_string(),
                 path: join_with_double_colon(&fqp[..fqp.len() - 1]),
                 desc,
-                parent: Some(did),
+                parent: Some(parent),
                 parent_idx: None,
-                search_type: get_function_type_for_search(item, tcx, cache),
+                search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
@@ -192,12 +192,13 @@ pub(crate) fn build_index<'tcx>(
 pub(crate) fn get_function_type_for_search<'tcx>(
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
+    impl_generics: Option<&(clean::Type, clean::Generics)>,
     cache: &Cache,
 ) -> Option<IndexItemFunctionType> {
     let (mut inputs, mut output) = match *item.kind {
-        clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache),
-        clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache),
-        clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache),
+        clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, impl_generics, cache),
+        clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
+        clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
         _ => return None,
     };
 
@@ -247,9 +248,10 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
 /// Important note: It goes through generics recursively. So if you have
 /// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
 #[instrument(level = "trace", skip(tcx, res, cache))]
-fn add_generics_and_bounds_as_types<'tcx>(
+fn add_generics_and_bounds_as_types<'tcx, 'a>(
+    self_: Option<&'a Type>,
     generics: &Generics,
-    arg: &Type,
+    arg: &'a Type,
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<TypeWithKind>,
@@ -334,6 +336,17 @@ fn add_generics_and_bounds_as_types<'tcx>(
         return;
     }
 
+    // First, check if it's "Self".
+    let arg = if let Some(self_) = self_ {
+        match &*arg {
+            Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
+            type_ if type_.is_self_type() => self_,
+            arg => arg,
+        }
+    } else {
+        arg
+    };
+
     // If this argument is a type parameter and not a trait bound or a type, we need to look
     // for its bounds.
     if let Type::Generic(arg_s) = *arg {
@@ -350,6 +363,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
                         match &param_def.kind {
                             clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
                                 add_generics_and_bounds_as_types(
+                                    self_,
                                     generics,
                                     ty,
                                     tcx,
@@ -372,6 +386,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::Path { path };
                     add_generics_and_bounds_as_types(
+                        self_,
                         generics,
                         &ty,
                         tcx,
@@ -393,6 +408,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
         if let Some(arg_generics) = arg.generics() {
             for gen in arg_generics.iter() {
                 add_generics_and_bounds_as_types(
+                    self_,
                     generics,
                     gen,
                     tcx,
@@ -413,18 +429,33 @@ fn add_generics_and_bounds_as_types<'tcx>(
 fn get_fn_inputs_and_outputs<'tcx>(
     func: &Function,
     tcx: TyCtxt<'tcx>,
+    impl_generics: Option<&(clean::Type, clean::Generics)>,
     cache: &Cache,
 ) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
     let decl = &func.decl;
-    let generics = &func.generics;
+
+    let combined_generics;
+    let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
+        match (impl_generics.is_empty(), func.generics.is_empty()) {
+            (true, _) => (Some(impl_self), &func.generics),
+            (_, true) => (Some(impl_self), impl_generics),
+            (false, false) => {
+                let mut params = func.generics.params.clone();
+                params.extend(impl_generics.params.clone());
+                let mut where_predicates = func.generics.where_predicates.clone();
+                where_predicates.extend(impl_generics.where_predicates.clone());
+                combined_generics = clean::Generics { params, where_predicates };
+                (Some(impl_self), &combined_generics)
+            }
+        }
+    } else {
+        (None, &func.generics)
+    };
 
     let mut all_types = Vec::new();
     for arg in decl.inputs.values.iter() {
-        if arg.type_.is_self_type() {
-            continue;
-        }
         let mut args = Vec::new();
-        add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache);
+        add_generics_and_bounds_as_types(self_, generics, &arg.type_, tcx, 0, &mut args, cache);
         if !args.is_empty() {
             all_types.extend(args);
         } else {
@@ -437,7 +468,15 @@ fn get_fn_inputs_and_outputs<'tcx>(
     let mut ret_types = Vec::new();
     match decl.output {
         FnRetTy::Return(ref return_type) => {
-            add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache);
+            add_generics_and_bounds_as_types(
+                self_,
+                generics,
+                return_type,
+                tcx,
+                0,
+                &mut ret_types,
+                cache,
+            );
             if ret_types.is_empty() {
                 if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) {
                     ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
diff --git a/src/test/rustdoc-js/generics-impl.js b/src/test/rustdoc-js/generics-impl.js
new file mode 100644
index 0000000000000..bb6e0041db5f2
--- /dev/null
+++ b/src/test/rustdoc-js/generics-impl.js
@@ -0,0 +1,57 @@
+// exact-check
+
+const QUERY = [
+    'Aaaaaaa -> u32',
+    'Aaaaaaa -> bool',
+    'Aaaaaaa -> usize',
+    'Read -> u64',
+    'bool -> u64',
+    'Ddddddd -> u64',
+    '-> Ddddddd'
+];
+
+const EXPECTED = [
+    {
+        // Aaaaaaa -> u32
+        'others': [
+            { 'path': 'generics_impl::Aaaaaaa', 'name': 'bbbbbbb' },
+        ],
+    },
+    {
+        // Aaaaaaa -> bool
+        'others': [
+            { 'path': 'generics_impl::Aaaaaaa', 'name': 'ccccccc' },
+        ],
+    },
+    {
+        // Aaaaaaa -> usize
+        'others': [
+            { 'path': 'generics_impl::Aaaaaaa', 'name': 'read' },
+        ],
+    },
+    {
+        // Read -> u64
+        'others': [
+            { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
+            { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
+        ],
+    },
+    {
+        // bool -> u64
+        'others': [
+            { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' },
+        ],
+    },
+    {
+        // Ddddddd -> u64
+        'others': [
+            { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
+        ],
+    },
+    {
+        // -> Ddddddd
+        'others': [
+            { 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/generics-impl.rs b/src/test/rustdoc-js/generics-impl.rs
new file mode 100644
index 0000000000000..696218021d5af
--- /dev/null
+++ b/src/test/rustdoc-js/generics-impl.rs
@@ -0,0 +1,35 @@
+use std::io::{Result as IoResult, Read};
+
+pub struct Aaaaaaa;
+
+impl Aaaaaaa {
+    pub fn bbbbbbb(self) -> u32 {
+        1
+    }
+    pub fn ccccccc(&self) -> bool {
+        true
+    }
+}
+
+impl Read for Aaaaaaa {
+    fn read(&mut self, out: &mut [u8]) -> IoResult<usize> {
+        Ok(out.len())
+    }
+}
+
+pub struct Ddddddd<T>(T);
+
+impl<T: Read> Ddddddd<T> {
+    pub fn eeeeeee(_: T) -> u64 {
+        1
+    }
+    pub fn fffffff(_: bool) -> u64 {
+        1
+    }
+    pub fn ggggggg(self) -> u64 {
+        1
+    }
+    pub fn hhhhhhh() -> Self where T: Default {
+        Ddddddd(T::default())
+    }
+}