about summary refs log tree commit diff
path: root/src/librustdoc/html/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/render')
-rw-r--r--src/librustdoc/html/render/mod.rs39
-rw-r--r--src/librustdoc/html/render/search_index.rs422
2 files changed, 396 insertions, 65 deletions
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 90691411f44..8b3cd9ca6fc 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -113,6 +113,7 @@ pub(crate) struct IndexItem {
 pub(crate) struct RenderType {
     id: Option<RenderTypeId>,
     generics: Option<Vec<RenderType>>,
+    bindings: Option<Vec<(RenderTypeId, Vec<RenderType>)>>,
 }
 
 impl Serialize for RenderType {
@@ -129,10 +130,15 @@ impl Serialize for RenderType {
             Some(RenderTypeId::Index(idx)) => *idx,
             _ => panic!("must convert render types to indexes before serializing"),
         };
-        if let Some(generics) = &self.generics {
+        if self.generics.is_some() || self.bindings.is_some() {
             let mut seq = serializer.serialize_seq(None)?;
             seq.serialize_element(&id)?;
-            seq.serialize_element(generics)?;
+            seq.serialize_element(self.generics.as_ref().map(Vec::as_slice).unwrap_or_default())?;
+            if self.bindings.is_some() {
+                seq.serialize_element(
+                    self.bindings.as_ref().map(Vec::as_slice).unwrap_or_default(),
+                )?;
+            }
             seq.end()
         } else {
             id.serialize(serializer)
@@ -140,13 +146,31 @@ impl Serialize for RenderType {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
 pub(crate) enum RenderTypeId {
     DefId(DefId),
     Primitive(clean::PrimitiveType),
+    AssociatedType(Symbol),
     Index(isize),
 }
 
+impl Serialize for RenderTypeId {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let id = match &self {
+            // 0 is a sentinel, everything else is one-indexed
+            // concrete type
+            RenderTypeId::Index(idx) if *idx >= 0 => idx + 1,
+            // generic type parameter
+            RenderTypeId::Index(idx) => *idx,
+            _ => panic!("must convert render types to indexes before serializing"),
+        };
+        id.serialize(serializer)
+    }
+}
+
 /// Full type of functions/methods in the search index.
 #[derive(Debug)]
 pub(crate) struct IndexItemFunctionType {
@@ -171,17 +195,22 @@ impl Serialize for IndexItemFunctionType {
         } else {
             let mut seq = serializer.serialize_seq(None)?;
             match &self.inputs[..] {
-                [one] if one.generics.is_none() => seq.serialize_element(one)?,
+                [one] if one.generics.is_none() && one.bindings.is_none() => {
+                    seq.serialize_element(one)?
+                }
                 _ => seq.serialize_element(&self.inputs)?,
             }
             match &self.output[..] {
                 [] if self.where_clause.is_empty() => {}
-                [one] if one.generics.is_none() => seq.serialize_element(one)?,
+                [one] if one.generics.is_none() && one.bindings.is_none() => {
+                    seq.serialize_element(one)?
+                }
                 _ => seq.serialize_element(&self.output)?,
             }
             for constraint in &self.where_clause {
                 if let [one] = &constraint[..]
                     && one.generics.is_none()
+                    && one.bindings.is_none()
                 {
                     seq.serialize_element(one)?;
                 } else {
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 1284f69e5d7..b3ae720fcf6 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -3,8 +3,10 @@ use std::collections::BTreeMap;
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_middle::ty::TyCtxt;
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
+use thin_vec::ThinVec;
 
 use crate::clean;
 use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
@@ -22,6 +24,7 @@ pub(crate) fn build_index<'tcx>(
 ) -> String {
     let mut itemid_to_pathid = FxHashMap::default();
     let mut primitives = FxHashMap::default();
+    let mut associated_types = FxHashMap::default();
     let mut crate_paths = vec![];
 
     // Attach all orphan items to the type's definition if the type
@@ -38,7 +41,13 @@ pub(crate) fn build_index<'tcx>(
                 parent: Some(parent),
                 parent_idx: None,
                 impl_id,
-                search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache),
+                search_type: get_function_type_for_search(
+                    item,
+                    tcx,
+                    impl_generics.as_ref(),
+                    Some(parent),
+                    cache,
+                ),
                 aliases: item.attrs.get_doc_aliases(),
                 deprecation: item.deprecation(tcx),
             });
@@ -76,83 +85,139 @@ pub(crate) fn build_index<'tcx>(
     let mut search_index = std::mem::replace(&mut cache.search_index, Vec::new());
     for item in search_index.iter_mut() {
         fn insert_into_map<F: std::hash::Hash + Eq>(
-            ty: &mut RenderType,
             map: &mut FxHashMap<F, isize>,
             itemid: F,
             lastpathid: &mut isize,
             crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
             item_type: ItemType,
             path: &[Symbol],
-        ) {
+        ) -> RenderTypeId {
             match map.entry(itemid) {
-                Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
+                Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()),
                 Entry::Vacant(entry) => {
                     let pathid = *lastpathid;
                     entry.insert(pathid);
                     *lastpathid += 1;
                     crate_paths.push((item_type, path.to_vec()));
-                    ty.id = Some(RenderTypeId::Index(pathid));
+                    RenderTypeId::Index(pathid)
                 }
             }
         }
 
-        fn convert_render_type(
-            ty: &mut RenderType,
+        fn convert_render_type_id(
+            id: RenderTypeId,
             cache: &mut Cache,
             itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
             primitives: &mut FxHashMap<Symbol, isize>,
+            associated_types: &mut FxHashMap<Symbol, isize>,
             lastpathid: &mut isize,
             crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
-        ) {
-            if let Some(generics) = &mut ty.generics {
-                for item in generics {
-                    convert_render_type(
-                        item,
-                        cache,
-                        itemid_to_pathid,
-                        primitives,
-                        lastpathid,
-                        crate_paths,
-                    );
-                }
-            }
+        ) -> Option<RenderTypeId> {
             let Cache { ref paths, ref external_paths, .. } = *cache;
-            let Some(id) = ty.id.clone() else {
-                assert!(ty.generics.is_some());
-                return;
-            };
             match id {
                 RenderTypeId::DefId(defid) => {
                     if let Some(&(ref fqp, item_type)) =
                         paths.get(&defid).or_else(|| external_paths.get(&defid))
                     {
-                        insert_into_map(
-                            ty,
+                        Some(insert_into_map(
                             itemid_to_pathid,
                             ItemId::DefId(defid),
                             lastpathid,
                             crate_paths,
                             item_type,
                             fqp,
-                        );
+                        ))
                     } else {
-                        ty.id = None;
+                        None
                     }
                 }
                 RenderTypeId::Primitive(primitive) => {
                     let sym = primitive.as_sym();
-                    insert_into_map(
-                        ty,
+                    Some(insert_into_map(
                         primitives,
                         sym,
                         lastpathid,
                         crate_paths,
                         ItemType::Primitive,
                         &[sym],
+                    ))
+                }
+                RenderTypeId::Index(_) => Some(id),
+                RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
+                    associated_types,
+                    sym,
+                    lastpathid,
+                    crate_paths,
+                    ItemType::AssocType,
+                    &[sym],
+                )),
+            }
+        }
+
+        fn convert_render_type(
+            ty: &mut RenderType,
+            cache: &mut Cache,
+            itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
+            primitives: &mut FxHashMap<Symbol, isize>,
+            associated_types: &mut FxHashMap<Symbol, isize>,
+            lastpathid: &mut isize,
+            crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
+        ) {
+            if let Some(generics) = &mut ty.generics {
+                for item in generics {
+                    convert_render_type(
+                        item,
+                        cache,
+                        itemid_to_pathid,
+                        primitives,
+                        associated_types,
+                        lastpathid,
+                        crate_paths,
                     );
                 }
-                RenderTypeId::Index(_) => {}
             }
+            if let Some(bindings) = &mut ty.bindings {
+                bindings.retain_mut(|(associated_type, constraints)| {
+                    let converted_associated_type = convert_render_type_id(
+                        *associated_type,
+                        cache,
+                        itemid_to_pathid,
+                        primitives,
+                        associated_types,
+                        lastpathid,
+                        crate_paths,
+                    );
+                    let Some(converted_associated_type) = converted_associated_type else {
+                        return false;
+                    };
+                    *associated_type = converted_associated_type;
+                    for constraint in constraints {
+                        convert_render_type(
+                            constraint,
+                            cache,
+                            itemid_to_pathid,
+                            primitives,
+                            associated_types,
+                            lastpathid,
+                            crate_paths,
+                        );
+                    }
+                    true
+                });
+            }
+            let Some(id) = ty.id.clone() else {
+                assert!(ty.generics.is_some());
+                return;
+            };
+            ty.id = convert_render_type_id(
+                id,
+                cache,
+                itemid_to_pathid,
+                primitives,
+                associated_types,
+                lastpathid,
+                crate_paths,
+            );
         }
         if let Some(search_type) = &mut item.search_type {
             for item in &mut search_type.inputs {
@@ -161,6 +226,7 @@ pub(crate) fn build_index<'tcx>(
                     cache,
                     &mut itemid_to_pathid,
                     &mut primitives,
+                    &mut associated_types,
                     &mut lastpathid,
                     &mut crate_paths,
                 );
@@ -171,6 +237,7 @@ pub(crate) fn build_index<'tcx>(
                     cache,
                     &mut itemid_to_pathid,
                     &mut primitives,
+                    &mut associated_types,
                     &mut lastpathid,
                     &mut crate_paths,
                 );
@@ -182,6 +249,7 @@ pub(crate) fn build_index<'tcx>(
                         cache,
                         &mut itemid_to_pathid,
                         &mut primitives,
+                        &mut associated_types,
                         &mut lastpathid,
                         &mut crate_paths,
                     );
@@ -442,12 +510,39 @@ pub(crate) fn get_function_type_for_search<'tcx>(
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
     impl_generics: Option<&(clean::Type, clean::Generics)>,
+    parent: Option<DefId>,
     cache: &Cache,
 ) -> Option<IndexItemFunctionType> {
+    let mut trait_info = None;
+    let impl_or_trait_generics = impl_generics.or_else(|| {
+        if let Some(def_id) = parent
+            && let Some(trait_) = cache.traits.get(&def_id)
+            && let Some((path, _)) =
+                cache.paths.get(&def_id).or_else(|| cache.external_paths.get(&def_id))
+        {
+            let path = clean::Path {
+                res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, def_id),
+                segments: path
+                    .iter()
+                    .map(|name| clean::PathSegment {
+                        name: *name,
+                        args: clean::GenericArgs::AngleBracketed {
+                            args: Vec::new().into_boxed_slice(),
+                            bindings: ThinVec::new(),
+                        },
+                    })
+                    .collect(),
+            };
+            trait_info = Some((clean::Type::Path { path }, trait_.generics.clone()));
+            Some(trait_info.as_ref().unwrap())
+        } else {
+            None
+        }
+    });
     let (mut inputs, mut output, where_clause) = match *item.kind {
-        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),
+        clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => {
+            get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
+        }
         _ => return None,
     };
 
@@ -457,14 +552,23 @@ pub(crate) fn get_function_type_for_search<'tcx>(
     Some(IndexItemFunctionType { inputs, output, where_clause })
 }
 
-fn get_index_type(clean_type: &clean::Type, generics: Vec<RenderType>) -> RenderType {
+fn get_index_type(
+    clean_type: &clean::Type,
+    generics: Vec<RenderType>,
+    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+) -> RenderType {
     RenderType {
-        id: get_index_type_id(clean_type),
+        id: get_index_type_id(clean_type, rgen),
         generics: if generics.is_empty() { None } else { Some(generics) },
+        bindings: None,
     }
 }
 
-fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
+fn get_index_type_id(
+    clean_type: &clean::Type,
+    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+) -> Option<RenderTypeId> {
+    use rustc_hir::def::{DefKind, Res};
     match *clean_type {
         clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
         clean::DynTrait(ref bounds, _) => {
@@ -472,18 +576,27 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
         }
         clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
         clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
-            get_index_type_id(type_)
+            get_index_type_id(type_, rgen)
         }
         // The type parameters are converted to generics in `simplify_fn_type`
         clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
         clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
         clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
+        clean::QPath(ref data) => {
+            if data.self_type.is_self_type()
+                && let Some(clean::Path { res: Res::Def(DefKind::Trait, trait_), .. }) = data.trait_
+            {
+                let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                let (idx, _) = rgen
+                    .entry(SimplifiedParam::AssociatedType(trait_, data.assoc.name))
+                    .or_insert_with(|| (idx, Vec::new()));
+                Some(RenderTypeId::Index(*idx))
+            } else {
+                None
+            }
+        }
         // Not supported yet
-        clean::BareFunction(_)
-        | clean::Generic(_)
-        | clean::ImplTrait(_)
-        | clean::QPath { .. }
-        | clean::Infer => None,
+        clean::BareFunction(_) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
     }
 }
 
@@ -493,6 +606,9 @@ enum SimplifiedParam {
     Symbol(Symbol),
     // every argument-position impl trait is its own type parameter
     Anonymous(isize),
+    // in a trait definition, the associated types are all bound to
+    // their own type parameter
+    AssociatedType(DefId, Symbol),
 }
 
 /// The point of this function is to lower generics and types into the simplified form that the
@@ -523,10 +639,17 @@ fn simplify_fn_type<'tcx, 'a>(
     }
 
     // First, check if it's "Self".
+    let mut is_self = false;
     let mut arg = if let Some(self_) = self_ {
         match &*arg {
-            Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
-            type_ if type_.is_self_type() => self_,
+            Type::BorrowedRef { type_, .. } if type_.is_self_type() => {
+                is_self = true;
+                self_
+            }
+            type_ if type_.is_self_type() => {
+                is_self = true;
+                self_
+            }
             arg => arg,
         }
     } else {
@@ -585,11 +708,19 @@ fn simplify_fn_type<'tcx, 'a>(
             }
         }
         if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
-            res.push(RenderType { id: Some(RenderTypeId::Index(*idx)), generics: None });
+            res.push(RenderType {
+                id: Some(RenderTypeId::Index(*idx)),
+                generics: None,
+                bindings: None,
+            });
         } else {
             let idx = -isize::try_from(rgen.len() + 1).unwrap();
             rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
-            res.push(RenderType { id: Some(RenderTypeId::Index(idx)), generics: None });
+            res.push(RenderType {
+                id: Some(RenderTypeId::Index(idx)),
+                generics: None,
+                bindings: None,
+            });
         }
     } else if let Type::ImplTrait(ref bounds) = *arg {
         let mut type_bounds = Vec::new();
@@ -611,12 +742,16 @@ fn simplify_fn_type<'tcx, 'a>(
         }
         if is_return && !type_bounds.is_empty() {
             // In parameter position, `impl Trait` is a unique thing.
-            res.push(RenderType { id: None, generics: Some(type_bounds) });
+            res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
         } else {
             // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
             let idx = -isize::try_from(rgen.len() + 1).unwrap();
             rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
-            res.push(RenderType { id: Some(RenderTypeId::Index(idx)), generics: None });
+            res.push(RenderType {
+                id: Some(RenderTypeId::Index(idx)),
+                generics: None,
+                bindings: None,
+            });
         }
     } else if let Type::Slice(ref ty) = *arg {
         let mut ty_generics = Vec::new();
@@ -631,7 +766,7 @@ fn simplify_fn_type<'tcx, 'a>(
             is_return,
             cache,
         );
-        res.push(get_index_type(arg, ty_generics));
+        res.push(get_index_type(arg, ty_generics, rgen));
     } else if let Type::Array(ref ty, _) = *arg {
         let mut ty_generics = Vec::new();
         simplify_fn_type(
@@ -645,7 +780,7 @@ fn simplify_fn_type<'tcx, 'a>(
             is_return,
             cache,
         );
-        res.push(get_index_type(arg, ty_generics));
+        res.push(get_index_type(arg, ty_generics, rgen));
     } else if let Type::Tuple(ref tys) = *arg {
         let mut ty_generics = Vec::new();
         for ty in tys {
@@ -661,7 +796,7 @@ fn simplify_fn_type<'tcx, 'a>(
                 cache,
             );
         }
-        res.push(get_index_type(arg, ty_generics));
+        res.push(get_index_type(arg, ty_generics, rgen));
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
         // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
@@ -669,12 +804,16 @@ fn simplify_fn_type<'tcx, 'a>(
         // So in here, we can add it directly and look for its own type parameters (so for `Option`,
         // we will look for them but not for `T`).
         let mut ty_generics = Vec::new();
-        if let Some(arg_generics) = arg.generics() {
-            for gen in arg_generics.iter() {
+        let mut ty_bindings = Vec::new();
+        if let Some(arg_generics) = arg.generic_args() {
+            for ty in arg_generics.into_iter().filter_map(|gen| match gen {
+                clean::GenericArg::Type(ty) => Some(ty),
+                _ => None,
+            }) {
                 simplify_fn_type(
                     self_,
                     generics,
-                    gen,
+                    &ty,
                     tcx,
                     recurse + 1,
                     &mut ty_generics,
@@ -683,17 +822,180 @@ fn simplify_fn_type<'tcx, 'a>(
                     cache,
                 );
             }
+            for binding in arg_generics.bindings() {
+                simplify_fn_binding(
+                    self_,
+                    generics,
+                    &binding,
+                    tcx,
+                    recurse + 1,
+                    &mut ty_bindings,
+                    rgen,
+                    is_return,
+                    cache,
+                );
+            }
+        }
+        // Every trait associated type on self gets assigned to a type parameter index
+        // this same one is used later for any appearances of these types
+        //
+        // for example, Iterator::next is:
+        //
+        //     trait Iterator {
+        //         fn next(&mut self) -> Option<Self::Item>
+        //     }
+        //
+        // Self is technically just Iterator, but we want to pretend it's more like this:
+        //
+        //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
+        if is_self
+            && let Type::Path { path } = arg
+            && let def_id = path.def_id()
+            && let Some(trait_) = cache.traits.get(&def_id)
+            && trait_.items.iter().any(|at| at.is_ty_associated_type())
+        {
+            for assoc_ty in &trait_.items {
+                if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
+                    && let Some(name) = assoc_ty.name
+                {
+                    let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                    let (idx, stored_bounds) = rgen
+                        .entry(SimplifiedParam::AssociatedType(def_id, name))
+                        .or_insert_with(|| (idx, Vec::new()));
+                    let idx = *idx;
+                    if stored_bounds.is_empty() {
+                        // Can't just pass stored_bounds to simplify_fn_type,
+                        // because it also accepts rgen as a parameter.
+                        // Instead, have it fill in this local, then copy it into the map afterward.
+                        let mut type_bounds = Vec::new();
+                        for bound in bounds {
+                            if let Some(path) = bound.get_trait_path() {
+                                let ty = Type::Path { path };
+                                simplify_fn_type(
+                                    self_,
+                                    generics,
+                                    &ty,
+                                    tcx,
+                                    recurse + 1,
+                                    &mut type_bounds,
+                                    rgen,
+                                    is_return,
+                                    cache,
+                                );
+                            }
+                        }
+                        let stored_bounds = &mut rgen
+                            .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
+                            .unwrap()
+                            .1;
+                        if stored_bounds.is_empty() {
+                            *stored_bounds = type_bounds;
+                        }
+                    }
+                    ty_bindings.push((
+                        RenderTypeId::AssociatedType(name),
+                        vec![RenderType {
+                            id: Some(RenderTypeId::Index(idx)),
+                            generics: None,
+                            bindings: None,
+                        }],
+                    ))
+                }
+            }
         }
-        let id = get_index_type_id(&arg);
+        let id = get_index_type_id(&arg, rgen);
         if id.is_some() || !ty_generics.is_empty() {
             res.push(RenderType {
                 id,
+                bindings: if ty_bindings.is_empty() { None } else { Some(ty_bindings) },
                 generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
             });
         }
     }
 }
 
+fn simplify_fn_binding<'tcx, 'a>(
+    self_: Option<&'a Type>,
+    generics: &Generics,
+    binding: &'a clean::TypeBinding,
+    tcx: TyCtxt<'tcx>,
+    recurse: usize,
+    res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
+    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+    is_return: bool,
+    cache: &Cache,
+) {
+    let mut ty_binding_constraints = Vec::new();
+    let ty_binding_assoc = RenderTypeId::AssociatedType(binding.assoc.name);
+    for gen in &binding.assoc.args {
+        match gen {
+            clean::GenericArg::Type(arg) => simplify_fn_type(
+                self_,
+                generics,
+                &arg,
+                tcx,
+                recurse + 1,
+                &mut ty_binding_constraints,
+                rgen,
+                is_return,
+                cache,
+            ),
+            clean::GenericArg::Lifetime(_)
+            | clean::GenericArg::Const(_)
+            | clean::GenericArg::Infer => {}
+        }
+    }
+    for binding in binding.assoc.args.bindings() {
+        simplify_fn_binding(
+            self_,
+            generics,
+            &binding,
+            tcx,
+            recurse + 1,
+            res,
+            rgen,
+            is_return,
+            cache,
+        );
+    }
+    match &binding.kind {
+        clean::TypeBindingKind::Equality { term } => {
+            if let clean::Term::Type(arg) = &term {
+                simplify_fn_type(
+                    self_,
+                    generics,
+                    arg,
+                    tcx,
+                    recurse + 1,
+                    &mut ty_binding_constraints,
+                    rgen,
+                    is_return,
+                    cache,
+                );
+            }
+        }
+        clean::TypeBindingKind::Constraint { bounds } => {
+            for bound in &bounds[..] {
+                if let Some(path) = bound.get_trait_path() {
+                    let ty = Type::Path { path };
+                    simplify_fn_type(
+                        self_,
+                        generics,
+                        &ty,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_binding_constraints,
+                        rgen,
+                        is_return,
+                        cache,
+                    );
+                }
+            }
+        }
+    }
+    res.push((ty_binding_assoc, ty_binding_constraints));
+}
+
 /// Return the full list of types when bounds have been resolved.
 ///
 /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
@@ -701,13 +1003,15 @@ fn simplify_fn_type<'tcx, 'a>(
 fn get_fn_inputs_and_outputs<'tcx>(
     func: &Function,
     tcx: TyCtxt<'tcx>,
-    impl_generics: Option<&(clean::Type, clean::Generics)>,
+    impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
     cache: &Cache,
 ) -> (Vec<RenderType>, Vec<RenderType>, Vec<Vec<RenderType>>) {
     let decl = &func.decl;
 
+    let mut rgen: FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
+
     let combined_generics;
-    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics {
+    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
         match (impl_generics.is_empty(), func.generics.is_empty()) {
             (true, _) => (Some(impl_self), &func.generics),
             (_, true) => (Some(impl_self), impl_generics),
@@ -729,8 +1033,6 @@ fn get_fn_inputs_and_outputs<'tcx>(
         (None, &func.generics)
     };
 
-    let mut rgen: FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
-
     let mut arg_types = Vec::new();
     for arg in decl.inputs.values.iter() {
         simplify_fn_type(