]> git.proxmox.com Git - rustc.git/blobdiff - src/librustdoc/clean/mod.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / src / librustdoc / clean / mod.rs
index 929f5f89b6357f319fc44c0ecd594b45b1a971b1..c8875c272bb08cb20d8d3c330d248a5d0fd832e6 100644 (file)
@@ -33,7 +33,8 @@ use std::collections::hash_map::Entry;
 use std::collections::BTreeMap;
 use std::default::Default;
 use std::hash::Hash;
-use std::{mem, vec};
+use std::mem;
+use thin_vec::ThinVec;
 
 use crate::core::{self, DocContext, ImplTraitParam};
 use crate::formats::item_type::ItemType;
@@ -44,128 +45,126 @@ use utils::*;
 pub(crate) use self::types::*;
 pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
 
-pub(crate) trait Clean<'tcx, T> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
-}
+pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let mut items: Vec<Item> = vec![];
+    let mut inserted = FxHashSet::default();
+    items.extend(doc.foreigns.iter().map(|(item, renamed)| {
+        let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+        if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
+            inserted.insert((item.type_(), name));
+        }
+        item
+    }));
+    items.extend(doc.mods.iter().filter_map(|x| {
+        if !inserted.insert((ItemType::Module, x.name)) {
+            return None;
+        }
+        let item = clean_doc_module(x, cx);
+        if item.attrs.lists(sym::doc).has_word(sym::hidden) {
+            // Hidden modules are stripped at a later stage.
+            // If a hidden module has the same name as a visible one, we want
+            // to keep both of them around.
+            inserted.remove(&(ItemType::Module, x.name));
+        }
+        Some(item)
+    }));
 
-impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let mut items: Vec<Item> = vec![];
-        let mut inserted = FxHashSet::default();
-        items.extend(self.foreigns.iter().map(|(item, renamed)| {
-            let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
-            if let Some(name) = item.name {
+    // Split up imports from all other items.
+    //
+    // This covers the case where somebody does an import which should pull in an item,
+    // but there's already an item with the same namespace and same name. Rust gives
+    // priority to the not-imported one, so we should, too.
+    items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+        // First, lower everything other than imports.
+        if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+            return Vec::new();
+        }
+        let v = clean_maybe_renamed_item(cx, item, *renamed);
+        for item in &v {
+            if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
                 inserted.insert((item.type_(), name));
             }
-            item
-        }));
-        items.extend(self.mods.iter().map(|x| {
-            inserted.insert((ItemType::Module, x.name));
-            x.clean(cx)
-        }));
-
-        // Split up imports from all other items.
-        //
-        // This covers the case where somebody does an import which should pull in an item,
-        // but there's already an item with the same namespace and same name. Rust gives
-        // priority to the not-imported one, so we should, too.
-        items.extend(self.items.iter().flat_map(|(item, renamed)| {
-            // First, lower everything other than imports.
-            if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
-                return Vec::new();
-            }
-            let v = clean_maybe_renamed_item(cx, item, *renamed);
-            for item in &v {
-                if let Some(name) = item.name {
-                    inserted.insert((item.type_(), name));
-                }
-            }
-            v
-        }));
-        items.extend(self.items.iter().flat_map(|(item, renamed)| {
-            // Now we actually lower the imports, skipping everything else.
-            if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
-                let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
-                clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
-            } else {
-                // skip everything else
-                Vec::new()
-            }
-        }));
-
-        // determine if we should display the inner contents or
-        // the outer `mod` item for the source code.
-
-        let span = Span::new({
-            let where_outer = self.where_outer(cx.tcx);
-            let sm = cx.sess().source_map();
-            let outer = sm.lookup_char_pos(where_outer.lo());
-            let inner = sm.lookup_char_pos(self.where_inner.lo());
-            if outer.file.start_pos == inner.file.start_pos {
-                // mod foo { ... }
-                where_outer
-            } else {
-                // mod foo; (and a separate SourceFile for the contents)
-                self.where_inner
-            }
-        });
+        }
+        v
+    }));
+    items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+        // Now we actually lower the imports, skipping everything else.
+        if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
+            let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
+            clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
+        } else {
+            // skip everything else
+            Vec::new()
+        }
+    }));
+
+    // determine if we should display the inner contents or
+    // the outer `mod` item for the source code.
+
+    let span = Span::new({
+        let where_outer = doc.where_outer(cx.tcx);
+        let sm = cx.sess().source_map();
+        let outer = sm.lookup_char_pos(where_outer.lo());
+        let inner = sm.lookup_char_pos(doc.where_inner.lo());
+        if outer.file.start_pos == inner.file.start_pos {
+            // mod foo { ... }
+            where_outer
+        } else {
+            // mod foo; (and a separate SourceFile for the contents)
+            doc.where_inner
+        }
+    });
 
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            ModuleItem(Module { items, span }),
-            cx,
-        )
-    }
+    Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx)
 }
 
-impl<'tcx> Clean<'tcx, Option<GenericBound>> for hir::GenericBound<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<GenericBound> {
-        Some(match *self {
-            hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
-            hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
-                let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
-
-                let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
-
-                let generic_args = generic_args.clean(cx);
-                let GenericArgs::AngleBracketed { bindings, .. } = generic_args
-                else {
-                    bug!("clean: parenthesized `GenericBound::LangItemTrait`");
-                };
+fn clean_generic_bound<'tcx>(
+    bound: &hir::GenericBound<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<GenericBound> {
+    Some(match *bound {
+        hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
+        hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
+            let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
+
+            let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
+
+            let generic_args = clean_generic_args(generic_args, cx);
+            let GenericArgs::AngleBracketed { bindings, .. } = generic_args
+            else {
+                bug!("clean: parenthesized `GenericBound::LangItemTrait`");
+            };
 
-                let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
-                GenericBound::TraitBound(
-                    PolyTrait { trait_, generic_params: vec![] },
-                    hir::TraitBoundModifier::None,
-                )
+            let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings);
+            GenericBound::TraitBound(
+                PolyTrait { trait_, generic_params: vec![] },
+                hir::TraitBoundModifier::None,
+            )
+        }
+        hir::GenericBound::Trait(ref t, modifier) => {
+            // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+            if modifier == hir::TraitBoundModifier::MaybeConst
+                && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
+            {
+                return None;
             }
-            hir::GenericBound::Trait(ref t, modifier) => {
-                // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-                if modifier == hir::TraitBoundModifier::MaybeConst
-                    && cx.tcx.lang_items().destruct_trait()
-                        == Some(t.trait_ref.trait_def_id().unwrap())
-                {
-                    return None;
-                }
 
-                GenericBound::TraitBound(t.clean(cx), modifier)
-            }
-        })
-    }
+            GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
+        }
+    })
 }
 
 pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
-    bindings: &[TypeBinding],
+    bindings: ThinVec<TypeBinding>,
 ) -> Path {
     let kind = cx.tcx.def_kind(trait_ref.def_id).into();
     if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
         span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
     }
     inline::record_extern_fqn(cx, trait_ref.def_id, kind);
-    let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs);
+    let path = external_path(cx, trait_ref.def_id, true, bindings, trait_ref.substs);
 
     debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
@@ -175,7 +174,7 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
 fn clean_poly_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    bindings: &[TypeBinding],
+    bindings: ThinVec<TypeBinding>,
 ) -> GenericBound {
     let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
 
@@ -200,16 +199,10 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
     )
 }
 
-impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound {
-        clean_poly_trait_ref_with_bindings(cx, *self, &[])
-    }
-}
-
-fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
     let def = cx.tcx.named_region(lifetime.hir_id);
     if let Some(
-        rl::Region::EarlyBound(_, node_id)
+        rl::Region::EarlyBound(node_id)
         | rl::Region::LateBound(_, _, node_id)
         | rl::Region::Free(_, node_id),
     ) = def
@@ -257,7 +250,6 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life
         | ty::ReFree(..)
         | ty::ReVar(..)
         | ty::RePlaceholder(..)
-        | ty::ReEmpty(_)
         | ty::ReErased => {
             debug!("cannot clean region {:?}", region);
             None
@@ -265,66 +257,68 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life
     }
 }
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        if !self.in_where_clause() {
-            return None;
-        }
-        Some(match *self {
-            hir::WherePredicate::BoundPredicate(ref wbp) => {
-                let bound_params = wbp
-                    .bound_generic_params
-                    .iter()
-                    .map(|param| {
-                        // Higher-ranked params must be lifetimes.
-                        // Higher-ranked lifetimes can't have bounds.
-                        assert_matches!(
-                            param,
-                            hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
-                        );
-                        Lifetime(param.name.ident().name)
-                    })
-                    .collect();
-                WherePredicate::BoundPredicate {
-                    ty: clean_ty(wbp.bounded_ty, cx),
-                    bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-                    bound_params,
-                }
+fn clean_where_predicate<'tcx>(
+    predicate: &hir::WherePredicate<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    if !predicate.in_where_clause() {
+        return None;
+    }
+    Some(match *predicate {
+        hir::WherePredicate::BoundPredicate(ref wbp) => {
+            let bound_params = wbp
+                .bound_generic_params
+                .iter()
+                .map(|param| {
+                    // Higher-ranked params must be lifetimes.
+                    // Higher-ranked lifetimes can't have bounds.
+                    assert_matches!(
+                        param,
+                        hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
+                    );
+                    Lifetime(param.name.ident().name)
+                })
+                .collect();
+            WherePredicate::BoundPredicate {
+                ty: clean_ty(wbp.bounded_ty, cx),
+                bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+                bound_params,
             }
+        }
 
-            hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
-                lifetime: clean_lifetime(wrp.lifetime, cx),
-                bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-            },
+        hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
+            lifetime: clean_lifetime(wrp.lifetime, cx),
+            bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+        },
 
-            hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
-                lhs: clean_ty(wrp.lhs_ty, cx),
-                rhs: clean_ty(wrp.rhs_ty, cx).into(),
-            },
-        })
-    }
+        hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+            lhs: clean_ty(wrp.lhs_ty, cx),
+            rhs: clean_ty(wrp.rhs_ty, cx).into(),
+        },
+    })
 }
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        let bound_predicate = self.kind();
-        match bound_predicate.skip_binder() {
-            ty::PredicateKind::Trait(pred) => {
-                clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
-            }
-            ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
-            ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
-            ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
-            ty::PredicateKind::ConstEvaluatable(..) => None,
-            ty::PredicateKind::WellFormed(..) => None,
-
-            ty::PredicateKind::Subtype(..)
-            | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::ConstEquate(..)
-            | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
+pub(crate) fn clean_predicate<'tcx>(
+    predicate: ty::Predicate<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    let bound_predicate = predicate.kind();
+    match bound_predicate.skip_binder() {
+        ty::PredicateKind::Trait(pred) => {
+            clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
         }
+        ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
+        ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
+        ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
+        ty::PredicateKind::ConstEvaluatable(..) => None,
+        ty::PredicateKind::WellFormed(..) => None,
+
+        ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::Coerce(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
     }
 }
 
@@ -342,7 +336,7 @@ fn clean_poly_trait_predicate<'tcx>(
     let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
-        bounds: vec![poly_trait_ref.clean(cx)],
+        bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, ThinVec::new())],
         bound_params: Vec::new(),
     })
 }
@@ -352,10 +346,6 @@ fn clean_region_outlives_predicate<'tcx>(
 ) -> Option<WherePredicate> {
     let ty::OutlivesPredicate(a, b) = pred;
 
-    if a.is_empty() && b.is_empty() {
-        return None;
-    }
-
     Some(WherePredicate::RegionPredicate {
         lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
         bounds: vec![GenericBound::Outlives(
@@ -370,10 +360,6 @@ fn clean_type_outlives_predicate<'tcx>(
 ) -> Option<WherePredicate> {
     let ty::OutlivesPredicate(ty, lt) = pred;
 
-    if lt.is_empty() {
-        return None;
-    }
-
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(ty, cx, None),
         bounds: vec![GenericBound::Outlives(
@@ -384,9 +370,9 @@ fn clean_type_outlives_predicate<'tcx>(
 }
 
 fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
-    match term {
-        ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
-        ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)),
+    match term.unpack() {
+        ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
+        ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)),
     }
 }
 
@@ -417,7 +403,7 @@ fn clean_projection<'tcx>(
     def_id: Option<DefId>,
 ) -> Type {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
-    let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]);
+    let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), ThinVec::new());
     let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
         cx.tcx.opt_parent(def_id).or(Some(def_id))
@@ -425,12 +411,12 @@ fn clean_projection<'tcx>(
         self_type.def_id(&cx.cache)
     };
     let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
-    Type::QPath {
-        assoc: Box::new(projection_to_path_segment(ty, cx)),
+    Type::QPath(Box::new(QPathData {
+        assoc: projection_to_path_segment(ty, cx),
         should_show_cast,
-        self_type: Box::new(self_type),
+        self_type,
         trait_,
-    }
+    }))
 }
 
 fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
@@ -509,7 +495,7 @@ fn clean_generic_param<'tcx>(
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
-                        hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
+                        hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx),
                         _ => panic!(),
                     })
                     .collect()
@@ -524,7 +510,7 @@ fn clean_generic_param<'tcx>(
                     .bounds_for_param(did)
                     .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
                     .flat_map(|bp| bp.bounds)
-                    .filter_map(|x| x.clean(cx))
+                    .filter_map(|x| clean_generic_bound(x, cx))
                     .collect()
             } else {
                 Vec::new()
@@ -572,65 +558,68 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
     matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
 }
 
-impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
-        let impl_trait_params = self
-            .params
-            .iter()
-            .filter(|param| is_impl_trait(param))
-            .map(|param| {
-                let param = clean_generic_param(cx, Some(self), param);
-                match param.kind {
-                    GenericParamDefKind::Lifetime { .. } => unreachable!(),
-                    GenericParamDefKind::Type { did, ref bounds, .. } => {
-                        cx.impl_trait_bounds.insert(did.into(), bounds.clone());
-                    }
-                    GenericParamDefKind::Const { .. } => unreachable!(),
+pub(crate) fn clean_generics<'tcx>(
+    gens: &hir::Generics<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Generics {
+    let impl_trait_params = gens
+        .params
+        .iter()
+        .filter(|param| is_impl_trait(param))
+        .map(|param| {
+            let param = clean_generic_param(cx, Some(gens), param);
+            match param.kind {
+                GenericParamDefKind::Lifetime { .. } => unreachable!(),
+                GenericParamDefKind::Type { did, ref bounds, .. } => {
+                    cx.impl_trait_bounds.insert(did.into(), bounds.clone());
                 }
-                param
-            })
-            .collect::<Vec<_>>();
+                GenericParamDefKind::Const { .. } => unreachable!(),
+            }
+            param
+        })
+        .collect::<Vec<_>>();
 
-        let mut params = Vec::with_capacity(self.params.len());
-        for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
-            let p = clean_generic_param(cx, Some(self), p);
-            params.push(p);
-        }
-        params.extend(impl_trait_params);
+    let mut params = Vec::with_capacity(gens.params.len());
+    for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
+        let p = clean_generic_param(cx, Some(gens), p);
+        params.push(p);
+    }
+    params.extend(impl_trait_params);
 
-        let mut generics = Generics {
-            params,
-            where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
-        };
+    let mut generics = Generics {
+        params,
+        where_predicates: gens
+            .predicates
+            .iter()
+            .filter_map(|x| clean_where_predicate(x, cx))
+            .collect(),
+    };
 
-        // Some duplicates are generated for ?Sized bounds between type params and where
-        // predicates. The point in here is to move the bounds definitions from type params
-        // to where predicates when such cases occur.
-        for where_pred in &mut generics.where_predicates {
-            match *where_pred {
-                WherePredicate::BoundPredicate {
-                    ty: Generic(ref name), ref mut bounds, ..
-                } => {
-                    if bounds.is_empty() {
-                        for param in &mut generics.params {
-                            match param.kind {
-                                GenericParamDefKind::Lifetime { .. } => {}
-                                GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
-                                    if &param.name == name {
-                                        mem::swap(bounds, ty_bounds);
-                                        break;
-                                    }
+    // Some duplicates are generated for ?Sized bounds between type params and where
+    // predicates. The point in here is to move the bounds definitions from type params
+    // to where predicates when such cases occur.
+    for where_pred in &mut generics.where_predicates {
+        match *where_pred {
+            WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
+                if bounds.is_empty() {
+                    for param in &mut generics.params {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime { .. } => {}
+                            GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
+                                if &param.name == name {
+                                    mem::swap(bounds, ty_bounds);
+                                    break;
                                 }
-                                GenericParamDefKind::Const { .. } => {}
                             }
+                            GenericParamDefKind::Const { .. } => {}
                         }
                     }
                 }
-                _ => continue,
             }
+            _ => continue,
         }
-        generics
     }
+    generics
 }
 
 fn clean_ty_generics<'tcx>(
@@ -701,7 +690,7 @@ fn clean_ty_generics<'tcx>(
 
             if let Some(param_idx) = param_idx {
                 if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
-                    let p: WherePredicate = p.clean(cx)?;
+                    let p: WherePredicate = clean_predicate(*p, cx)?;
 
                     b.extend(
                         p.get_bounds()
@@ -758,7 +747,7 @@ fn clean_ty_generics<'tcx>(
     // Now that `cx.impl_trait_bounds` is populated, we can process
     // remaining predicates which could contain `impl Trait`.
     let mut where_predicates =
-        where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
+        where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
 
     // Type parameters have a Sized bound by default unless removed with
     // ?Sized. Scan through the predicates and mark any type parameter with
@@ -896,9 +885,12 @@ fn clean_function<'tcx>(
 ) -> Box<Function> {
     let (generics, decl) = enter_impl_trait(cx, |cx| {
         // NOTE: generics must be cleaned before args
-        let generics = generics.clean(cx);
+        let generics = clean_generics(generics, cx);
         let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
-        let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+        let mut decl = clean_fn_decl_with_args(cx, sig.decl, args);
+        if sig.header.is_async() {
+            decl.output = decl.sugared_async_return_type();
+        }
         (generics, decl)
     });
     Box::new(Function { decl, generics })
@@ -994,305 +986,307 @@ fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'t
     path
 }
 
-impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait {
-        PolyTrait {
-            trait_: clean_trait_ref(&self.trait_ref, cx),
-            generic_params: self
-                .bound_generic_params
-                .iter()
-                .filter(|p| !is_elided_lifetime(p))
-                .map(|x| clean_generic_param(cx, None, x))
-                .collect(),
-        }
+fn clean_poly_trait_ref<'tcx>(
+    poly_trait_ref: &hir::PolyTraitRef<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> PolyTrait {
+    PolyTrait {
+        trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx),
+        generic_params: poly_trait_ref
+            .bound_generic_params
+            .iter()
+            .filter(|p| !is_elided_lifetime(p))
+            .map(|x| clean_generic_param(cx, None, x))
+            .collect(),
     }
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, |cx| {
-            let inner = match self.kind {
-                hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
-                    clean_ty(ty, cx),
-                    ConstantKind::Local { def_id: local_did, body: default },
-                ),
-                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    let m = clean_function(cx, sig, self.generics, body);
-                    MethodItem(m, None)
-                }
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
-                    let (generics, decl) = enter_impl_trait(cx, |cx| {
-                        // NOTE: generics must be cleaned before args
-                        let generics = self.generics.clean(cx);
-                        let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
-                        let decl = clean_fn_decl_with_args(cx, sig.decl, args);
-                        (generics, decl)
-                    });
-                    TyMethodItem(Box::new(Function { decl, generics }))
-                }
-                hir::TraitItemKind::Type(bounds, Some(default)) => {
-                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
-                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
-                    AssocTypeItem(
-                        Box::new(Typedef {
-                            type_: clean_ty(default, cx),
-                            generics,
-                            item_type: Some(item_type),
-                        }),
-                        bounds,
-                    )
-                }
-                hir::TraitItemKind::Type(bounds, None) => {
-                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
-                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    TyAssocTypeItem(Box::new(generics), bounds)
-                }
-            };
-            let what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
-            // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
-            Item { visibility: Inherited, ..what_rustc_thinks }
-        })
-    }
+fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let local_did = trait_item.def_id.to_def_id();
+    cx.with_param_env(local_did, |cx| {
+        let inner = match trait_item.kind {
+            hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
+                clean_ty(ty, cx),
+                ConstantKind::Local { def_id: local_did, body: default },
+            ),
+            hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+                let m = clean_function(cx, sig, trait_item.generics, body);
+                MethodItem(m, None)
+            }
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
+                let (generics, decl) = enter_impl_trait(cx, |cx| {
+                    // NOTE: generics must be cleaned before args
+                    let generics = clean_generics(trait_item.generics, cx);
+                    let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
+                    let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+                    (generics, decl)
+                });
+                TyMethodItem(Box::new(Function { decl, generics }))
+            }
+            hir::TraitItemKind::Type(bounds, Some(default)) => {
+                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+                let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+                let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
+                AssocTypeItem(
+                    Box::new(Typedef {
+                        type_: clean_ty(default, cx),
+                        generics,
+                        item_type: Some(item_type),
+                    }),
+                    bounds,
+                )
+            }
+            hir::TraitItemKind::Type(bounds, None) => {
+                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+                let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+                TyAssocTypeItem(Box::new(generics), bounds)
+            }
+        };
+        let what_rustc_thinks =
+            Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx);
+        // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
+        Item { visibility: Inherited, ..what_rustc_thinks }
+    })
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, |cx| {
-            let inner = match self.kind {
-                hir::ImplItemKind::Const(ty, expr) => {
-                    let default = ConstantKind::Local { def_id: local_did, body: expr };
-                    AssocConstItem(clean_ty(ty, cx), default)
-                }
-                hir::ImplItemKind::Fn(ref sig, body) => {
-                    let m = clean_function(cx, sig, self.generics, body);
-                    let defaultness = cx.tcx.impl_defaultness(self.def_id);
-                    MethodItem(m, Some(defaultness))
-                }
-                hir::ImplItemKind::TyAlias(hir_ty) => {
-                    let type_ = clean_ty(hir_ty, cx);
-                    let generics = self.generics.clean(cx);
-                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
-                    AssocTypeItem(
-                        Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
-                        Vec::new(),
-                    )
-                }
-            };
+pub(crate) fn clean_impl_item<'tcx>(
+    impl_: &hir::ImplItem<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let local_did = impl_.def_id.to_def_id();
+    cx.with_param_env(local_did, |cx| {
+        let inner = match impl_.kind {
+            hir::ImplItemKind::Const(ty, expr) => {
+                let default = ConstantKind::Local { def_id: local_did, body: expr };
+                AssocConstItem(clean_ty(ty, cx), default)
+            }
+            hir::ImplItemKind::Fn(ref sig, body) => {
+                let m = clean_function(cx, sig, impl_.generics, body);
+                let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+                MethodItem(m, Some(defaultness))
+            }
+            hir::ImplItemKind::TyAlias(hir_ty) => {
+                let type_ = clean_ty(hir_ty, cx);
+                let generics = clean_generics(impl_.generics, cx);
+                let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
+                AssocTypeItem(
+                    Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
+                    Vec::new(),
+                )
+            }
+        };
 
-            let mut what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
+        let mut what_rustc_thinks =
+            Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
 
-            let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
+        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id));
 
-            // Trait impl items always inherit the impl's visibility --
-            // we don't want to show `pub`.
-            if impl_ref.is_some() {
-                what_rustc_thinks.visibility = Inherited;
-            }
+        // Trait impl items always inherit the impl's visibility --
+        // we don't want to show `pub`.
+        if impl_ref.is_some() {
+            what_rustc_thinks.visibility = Inherited;
+        }
 
-            what_rustc_thinks
-        })
-    }
+        what_rustc_thinks
+    })
 }
 
-impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let tcx = cx.tcx;
-        let kind = match self.kind {
-            ty::AssocKind::Const => {
-                let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
+pub(crate) fn clean_middle_assoc_item<'tcx>(
+    assoc_item: &ty::AssocItem,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let tcx = cx.tcx;
+    let kind = match assoc_item.kind {
+        ty::AssocKind::Const => {
+            let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id));
 
-                let provided = match self.container {
-                    ty::ImplContainer => true,
-                    ty::TraitContainer => tcx.impl_defaultness(self.def_id).has_value(),
-                };
-                if provided {
-                    AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
-                } else {
-                    TyAssocConstItem(ty)
-                }
+            let provided = match assoc_item.container {
+                ty::ImplContainer => true,
+                ty::TraitContainer => tcx.impl_defaultness(assoc_item.def_id).has_value(),
+            };
+            if provided {
+                AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
+            } else {
+                TyAssocConstItem(ty)
             }
-            ty::AssocKind::Fn => {
-                let generics = clean_ty_generics(
-                    cx,
-                    tcx.generics_of(self.def_id),
-                    tcx.explicit_predicates_of(self.def_id),
-                );
-                let sig = tcx.fn_sig(self.def_id);
-                let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig);
-
-                if self.fn_has_self_parameter {
-                    let self_ty = match self.container {
-                        ty::ImplContainer => tcx.type_of(self.container_id(tcx)),
-                        ty::TraitContainer => tcx.types.self_param,
-                    };
-                    let self_arg_ty = sig.input(0).skip_binder();
-                    if self_arg_ty == self_ty {
-                        decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
-                    } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
-                        if ty == self_ty {
-                            match decl.inputs.values[0].type_ {
-                                BorrowedRef { ref mut type_, .. } => {
-                                    **type_ = Generic(kw::SelfUpper)
-                                }
-                                _ => unreachable!(),
-                            }
+        }
+        ty::AssocKind::Fn => {
+            let generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(assoc_item.def_id),
+                tcx.explicit_predicates_of(assoc_item.def_id),
+            );
+            let sig = tcx.fn_sig(assoc_item.def_id);
+            let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
+
+            if assoc_item.fn_has_self_parameter {
+                let self_ty = match assoc_item.container {
+                    ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)),
+                    ty::TraitContainer => tcx.types.self_param,
+                };
+                let self_arg_ty = sig.input(0).skip_binder();
+                if self_arg_ty == self_ty {
+                    decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
+                } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
+                    if ty == self_ty {
+                        match decl.inputs.values[0].type_ {
+                            BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
+                            _ => unreachable!(),
                         }
                     }
                 }
+            }
 
-                let provided = match self.container {
-                    ty::ImplContainer => true,
-                    ty::TraitContainer => self.defaultness(tcx).has_value(),
+            let provided = match assoc_item.container {
+                ty::ImplContainer => true,
+                ty::TraitContainer => assoc_item.defaultness(tcx).has_value(),
+            };
+            if provided {
+                let defaultness = match assoc_item.container {
+                    ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
+                    ty::TraitContainer => None,
                 };
-                if provided {
-                    let defaultness = match self.container {
-                        ty::ImplContainer => Some(self.defaultness(tcx)),
-                        ty::TraitContainer => None,
-                    };
-                    MethodItem(Box::new(Function { generics, decl }), defaultness)
-                } else {
-                    TyMethodItem(Box::new(Function { generics, decl }))
-                }
+                MethodItem(Box::new(Function { generics, decl }), defaultness)
+            } else {
+                TyMethodItem(Box::new(Function { generics, decl }))
             }
-            ty::AssocKind::Type => {
-                let my_name = self.name;
-
-                fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
-                    match (&param.kind, arg) {
-                        (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
-                            if *ty == param.name =>
-                        {
-                            true
-                        }
-                        (
-                            GenericParamDefKind::Lifetime { .. },
-                            GenericArg::Lifetime(Lifetime(lt)),
-                        ) if *lt == param.name => true,
-                        (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => {
-                            match &c.kind {
-                                ConstantKind::TyConst { expr } => expr == param.name.as_str(),
-                                _ => false,
-                            }
-                        }
-                        _ => false,
+        }
+        ty::AssocKind::Type => {
+            let my_name = assoc_item.name;
+
+            fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
+                match (&param.kind, arg) {
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
+                        if *ty == param.name =>
+                    {
+                        true
+                    }
+                    (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt)))
+                        if *lt == param.name =>
+                    {
+                        true
                     }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
+                        ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+                        _ => false,
+                    },
+                    _ => false,
                 }
+            }
 
-                if let ty::TraitContainer = self.container {
-                    let bounds = tcx.explicit_item_bounds(self.def_id);
-                    let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                    let mut generics =
-                        clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
-                    // Filter out the bounds that are (likely?) directly attached to the associated type,
-                    // as opposed to being located in the where clause.
-                    let mut bounds = generics
-                        .where_predicates
-                        .drain_filter(|pred| match *pred {
-                            WherePredicate::BoundPredicate {
-                                ty: QPath { ref assoc, ref self_type, ref trait_, .. },
-                                ..
-                            } => {
-                                if assoc.name != my_name {
-                                    return false;
-                                }
-                                if trait_.def_id() != self.container_id(tcx) {
-                                    return false;
-                                }
-                                match **self_type {
-                                    Generic(ref s) if *s == kw::SelfUpper => {}
-                                    _ => return false,
-                                }
-                                match &assoc.args {
-                                    GenericArgs::AngleBracketed { args, bindings } => {
-                                        if !bindings.is_empty()
-                                            || generics
-                                                .params
-                                                .iter()
-                                                .zip(args.iter())
-                                                .any(|(param, arg)| !param_eq_arg(param, arg))
-                                        {
-                                            return false;
-                                        }
-                                    }
-                                    GenericArgs::Parenthesized { .. } => {
-                                        // The only time this happens is if we're inside the rustdoc for Fn(),
-                                        // which only has one associated type, which is not a GAT, so whatever.
+            if let ty::TraitContainer = assoc_item.container {
+                let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
+                let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
+                let mut generics =
+                    clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates);
+                // Filter out the bounds that are (likely?) directly attached to the associated type,
+                // as opposed to being located in the where clause.
+                let mut bounds = generics
+                    .where_predicates
+                    .drain_filter(|pred| match *pred {
+                        WherePredicate::BoundPredicate {
+                            ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }),
+                            ..
+                        } => {
+                            if assoc.name != my_name {
+                                return false;
+                            }
+                            if trait_.def_id() != assoc_item.container_id(tcx) {
+                                return false;
+                            }
+                            match *self_type {
+                                Generic(ref s) if *s == kw::SelfUpper => {}
+                                _ => return false,
+                            }
+                            match &assoc.args {
+                                GenericArgs::AngleBracketed { args, bindings } => {
+                                    if !bindings.is_empty()
+                                        || generics
+                                            .params
+                                            .iter()
+                                            .zip(args.iter())
+                                            .any(|(param, arg)| !param_eq_arg(param, arg))
+                                    {
+                                        return false;
                                     }
                                 }
-                                true
-                            }
-                            _ => false,
-                        })
-                        .flat_map(|pred| {
-                            if let WherePredicate::BoundPredicate { bounds, .. } = pred {
-                                bounds
-                            } else {
-                                unreachable!()
+                                GenericArgs::Parenthesized { .. } => {
+                                    // The only time this happens is if we're inside the rustdoc for Fn(),
+                                    // which only has one associated type, which is not a GAT, so whatever.
+                                }
                             }
-                        })
-                        .collect::<Vec<_>>();
-                    // Our Sized/?Sized bound didn't get handled when creating the generics
-                    // because we didn't actually get our whole set of bounds until just now
-                    // (some of them may have come from the trait). If we do have a sized
-                    // bound, we remove it, and if we don't then we add the `?Sized` bound
-                    // at the end.
-                    match bounds.iter().position(|b| b.is_sized_bound(cx)) {
-                        Some(i) => {
-                            bounds.remove(i);
+                            true
                         }
-                        None => bounds.push(GenericBound::maybe_sized(cx)),
+                        _ => false,
+                    })
+                    .flat_map(|pred| {
+                        if let WherePredicate::BoundPredicate { bounds, .. } = pred {
+                            bounds
+                        } else {
+                            unreachable!()
+                        }
+                    })
+                    .collect::<Vec<_>>();
+                // Our Sized/?Sized bound didn't get handled when creating the generics
+                // because we didn't actually get our whole set of bounds until just now
+                // (some of them may have come from the trait). If we do have a sized
+                // bound, we remove it, and if we don't then we add the `?Sized` bound
+                // at the end.
+                match bounds.iter().position(|b| b.is_sized_bound(cx)) {
+                    Some(i) => {
+                        bounds.remove(i);
                     }
+                    None => bounds.push(GenericBound::maybe_sized(cx)),
+                }
 
-                    if tcx.impl_defaultness(self.def_id).has_value() {
-                        AssocTypeItem(
-                            Box::new(Typedef {
-                                type_: clean_middle_ty(
-                                    tcx.type_of(self.def_id),
-                                    cx,
-                                    Some(self.def_id),
-                                ),
-                                generics,
-                                // FIXME: should we obtain the Type from HIR and pass it on here?
-                                item_type: None,
-                            }),
-                            bounds,
-                        )
-                    } else {
-                        TyAssocTypeItem(Box::new(generics), bounds)
-                    }
-                } else {
-                    // FIXME: when could this happen? Associated items in inherent impls?
+                if tcx.impl_defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
                         Box::new(Typedef {
-                            type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
-                            generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+                            type_: clean_middle_ty(
+                                tcx.type_of(assoc_item.def_id),
+                                cx,
+                                Some(assoc_item.def_id),
+                            ),
+                            generics,
+                            // FIXME: should we obtain the Type from HIR and pass it on here?
                             item_type: None,
                         }),
-                        Vec::new(),
+                        bounds,
                     )
+                } else {
+                    TyAssocTypeItem(Box::new(generics), bounds)
                 }
+            } else {
+                // FIXME: when could this happen? Associated items in inherent impls?
+                AssocTypeItem(
+                    Box::new(Typedef {
+                        type_: clean_middle_ty(
+                            tcx.type_of(assoc_item.def_id),
+                            cx,
+                            Some(assoc_item.def_id),
+                        ),
+                        generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+                        item_type: None,
+                    }),
+                    Vec::new(),
+                )
             }
-        };
+        }
+    };
 
-        let mut what_rustc_thinks =
-            Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
+    let mut what_rustc_thinks =
+        Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx);
 
-        let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
+    let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id));
 
-        // Trait impl items always inherit the impl's visibility --
-        // we don't want to show `pub`.
-        if impl_ref.is_some() {
-            what_rustc_thinks.visibility = Visibility::Inherited;
-        }
-
-        what_rustc_thinks
+    // Trait impl items always inherit the impl's visibility --
+    // we don't want to show `pub`.
+    if impl_ref.is_some() {
+        what_rustc_thinks.visibility = Visibility::Inherited;
     }
+
+    what_rustc_thinks
 }
 
 fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
@@ -1328,18 +1322,18 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             let trait_def = cx.tcx.associated_item(p.res.def_id()).container_id(cx.tcx);
             let trait_ = self::Path {
                 res: Res::Def(DefKind::Trait, trait_def),
-                segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
+                segments: trait_segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
             };
             register_res(cx, trait_.res);
             let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
             let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
-            Type::QPath {
-                assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)),
+            Type::QPath(Box::new(QPathData {
+                assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx),
                 should_show_cast,
-                self_type: Box::new(self_type),
+                self_type,
                 trait_,
-            }
+            }))
         }
         hir::QPath::TypeRelative(qself, segment) => {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
@@ -1354,12 +1348,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             let self_def_id = res.opt_def_id();
             let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
-            Type::QPath {
-                assoc: Box::new(segment.clean(cx)),
+            Type::QPath(Box::new(QPathData {
+                assoc: clean_path_segment(segment, cx),
                 should_show_cast,
-                self_type: Box::new(self_type),
+                self_type,
                 trait_,
-            }
+            }))
         }
         hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
     }
@@ -1398,7 +1392,7 @@ fn maybe_expand_private_type_alias<'tcx>(
                     }
                     _ => None,
                 });
-                if let Some(lt) = lifetime.cloned() {
+                if let Some(lt) = lifetime {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                     let cleaned =
                         if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
@@ -1498,22 +1492,22 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             Array(Box::new(clean_ty(ty, cx)), length)
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
-        TyKind::OpaqueDef(item_id, _) => {
+        TyKind::OpaqueDef(item_id, _, _) => {
             let item = cx.tcx.hir().item(item_id);
             if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
-                ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
+                ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
             } else {
                 unreachable!()
             }
         }
         TyKind::Path(_) => clean_qpath(ty, cx),
         TyKind::TraitObject(bounds, ref lifetime, _) => {
-            let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
+            let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
             let lifetime =
                 if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
             DynTrait(bounds, lifetime)
         }
-        TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
+        TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
         // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
         TyKind::Infer | TyKind::Err => Infer,
         TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind),
@@ -1598,21 +1592,22 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 AdtKind::Enum => ItemType::Enum,
             };
             inline::record_extern_fqn(cx, did, kind);
-            let path = external_path(cx, did, false, vec![], substs);
+            let path = external_path(cx, did, false, ThinVec::new(), substs);
             Type::Path { path }
         }
         ty::Foreign(did) => {
             inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-            let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
+            let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty());
             Type::Path { path }
         }
-        ty::Dynamic(obj, ref reg) => {
+        ty::Dynamic(obj, ref reg, _) => {
             // HACK: pick the first `did` as the `did` of the trait object. Someone
             // might want to implement "native" support for marker-trait-only
             // trait objects.
-            let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
-            let did = dids
-                .next()
+            let mut dids = obj.auto_traits();
+            let did = obj
+                .principal_def_id()
+                .or_else(|| dids.next())
                 .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
             let substs = match obj.principal() {
                 Some(principal) => principal.skip_binder().substs,
@@ -1623,19 +1618,18 @@ pub(crate) fn clean_middle_ty<'tcx>(
             inline::record_extern_fqn(cx, did, ItemType::Trait);
 
             let lifetime = clean_middle_region(*reg);
-            let mut bounds = vec![];
-
-            for did in dids {
-                let empty = cx.tcx.intern_substs(&[]);
-                let path = external_path(cx, did, false, vec![], empty);
-                inline::record_extern_fqn(cx, did, ItemType::Trait);
-                let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
-                bounds.push(bound);
-            }
+            let mut bounds = dids
+                .map(|did| {
+                    let empty = cx.tcx.intern_substs(&[]);
+                    let path = external_path(cx, did, false, ThinVec::new(), empty);
+                    inline::record_extern_fqn(cx, did, ItemType::Trait);
+                    PolyTrait { trait_: path, generic_params: Vec::new() }
+                })
+                .collect::<Vec<_>>();
 
-            let mut bindings = vec![];
-            for pb in obj.projection_bounds() {
-                bindings.push(TypeBinding {
+            let bindings = obj
+                .projection_bounds()
+                .map(|pb| TypeBinding {
                     assoc: projection_to_path_segment(
                         pb.skip_binder()
                             .lift_to_tcx(cx.tcx)
@@ -1649,8 +1643,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
                     kind: TypeBindingKind::Equality {
                         term: clean_middle_term(pb.skip_binder().term, cx),
                     },
-                });
-            }
+                })
+                .collect();
 
             let path = external_path(cx, did, false, bindings, substs);
             bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
@@ -1703,7 +1697,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                         }
                     }
 
-                    let bindings: Vec<_> = bounds
+                    let bindings: ThinVec<_> = bounds
                         .iter()
                         .filter_map(|bound| {
                             if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
@@ -1724,7 +1718,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                         })
                         .collect();
 
-                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
+                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
                 })
                 .collect::<Vec<_>>();
             bounds.extend(regions);
@@ -1783,21 +1777,19 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
+pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility {
     match vis {
         ty::Visibility::Public => Visibility::Public,
-        // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
-        // while rustdoc really does mean inherited. That means that for enum variants, such as
-        // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
-        // Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured.
-        ty::Visibility::Invisible => Visibility::Inherited,
         ty::Visibility::Restricted(module) => Visibility::Restricted(module),
     }
 }
 
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
     let kind = match variant.ctor_kind {
-        CtorKind::Const => Variant::CLike,
+        CtorKind::Const => Variant::CLike(match variant.discr {
+            ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+            ty::VariantDiscr::Relative(_) => None,
+        }),
         CtorKind::Fn => Variant::Tuple(
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
@@ -1814,6 +1806,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont
 
 fn clean_variant_data<'tcx>(
     variant: &hir::VariantData<'tcx>,
+    disr_expr: &Option<hir::AnonConst>,
     cx: &mut DocContext<'tcx>,
 ) -> Variant {
     match variant {
@@ -1824,66 +1817,75 @@ fn clean_variant_data<'tcx>(
         hir::VariantData::Tuple(..) => {
             Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
         }
-        hir::VariantData::Unit(..) => Variant::CLike,
+        hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
+            expr: Some(disr.body),
+            value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+        })),
     }
 }
 
 fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
-    Path { res: path.res, segments: path.segments.iter().map(|x| x.clean(cx)).collect() }
+    Path {
+        res: path.res,
+        segments: path.segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
+    }
 }
 
-impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
-        if self.parenthesized {
-            let output = clean_ty(self.bindings[0].ty(), cx);
-            let output =
-                if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
-            let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
-            GenericArgs::Parenthesized { inputs, output }
-        } else {
-            let args = self
-                .args
-                .iter()
-                .map(|arg| match arg {
-                    hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
-                        GenericArg::Lifetime(clean_lifetime(*lt, cx))
-                    }
-                    hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
-                    hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
-                    hir::GenericArg::Infer(_inf) => GenericArg::Infer,
-                })
-                .collect::<Vec<_>>()
-                .into();
-            let bindings =
-                self.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<Vec<_>>().into();
-            GenericArgs::AngleBracketed { args, bindings }
-        }
+fn clean_generic_args<'tcx>(
+    generic_args: &hir::GenericArgs<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> GenericArgs {
+    if generic_args.parenthesized {
+        let output = clean_ty(generic_args.bindings[0].ty(), cx);
+        let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
+        let inputs =
+            generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
+        GenericArgs::Parenthesized { inputs, output }
+    } else {
+        let args = generic_args
+            .args
+            .iter()
+            .map(|arg| match arg {
+                hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+                    GenericArg::Lifetime(clean_lifetime(*lt, cx))
+                }
+                hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
+                hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+                hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+            })
+            .collect::<Vec<_>>()
+            .into();
+        let bindings =
+            generic_args.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<ThinVec<_>>();
+        GenericArgs::AngleBracketed { args, bindings }
     }
 }
 
-impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment {
-        PathSegment { name: self.ident.name, args: self.args().clean(cx) }
-    }
+fn clean_path_segment<'tcx>(
+    path: &hir::PathSegment<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> PathSegment {
+    PathSegment { name: path.ident.name, args: clean_generic_args(path.args(), cx) }
 }
 
-impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl {
-        let (generic_params, decl) = enter_impl_trait(cx, |cx| {
-            // NOTE: generics must be cleaned before args
-            let generic_params = self
-                .generic_params
-                .iter()
-                .filter(|p| !is_elided_lifetime(p))
-                .map(|x| clean_generic_param(cx, None, x))
-                .collect();
-            let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
-            let decl = clean_fn_decl_with_args(cx, self.decl, args);
-            (generic_params, decl)
-        });
-        BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
-    }
+fn clean_bare_fn_ty<'tcx>(
+    bare_fn: &hir::BareFnTy<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> BareFunctionDecl {
+    let (generic_params, decl) = enter_impl_trait(cx, |cx| {
+        // NOTE: generics must be cleaned before args
+        let generic_params = bare_fn
+            .generic_params
+            .iter()
+            .filter(|p| !is_elided_lifetime(p))
+            .map(|x| clean_generic_param(cx, None, x))
+            .collect();
+        let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names);
+        let decl = clean_fn_decl_with_args(cx, bare_fn.decl, args);
+        (generic_params, decl)
+    });
+    BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
 }
 
 fn clean_maybe_renamed_item<'tcx>(
@@ -1905,33 +1907,33 @@ fn clean_maybe_renamed_item<'tcx>(
                 kind: ConstantKind::Local { body: body_id, def_id },
             }),
             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
-                bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-                generics: ty.generics.clean(cx),
+                bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+                generics: clean_generics(ty.generics, cx),
             }),
             ItemKind::TyAlias(hir_ty, generics) => {
                 let rustdoc_ty = clean_ty(hir_ty, cx);
                 let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                 TypedefItem(Box::new(Typedef {
                     type_: rustdoc_ty,
-                    generics: generics.clean(cx),
+                    generics: clean_generics(generics, cx),
                     item_type: Some(ty),
                 }))
             }
             ItemKind::Enum(ref def, generics) => EnumItem(Enum {
-                variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
-                generics: generics.clean(cx),
+                variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
+                generics: clean_generics(generics, cx),
             }),
             ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
-                generics: generics.clean(cx),
-                bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                generics: clean_generics(generics, cx),
+                bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
             }),
             ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
                 struct_type: CtorKind::from_hir(variant_data),
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
@@ -1946,15 +1948,17 @@ fn clean_maybe_renamed_item<'tcx>(
                 })
             }
             ItemKind::Trait(_, _, generics, bounds, item_ids) => {
-                let items =
-                    item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+                let items = item_ids
+                    .iter()
+                    .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx))
+                    .collect();
 
-                TraitItem(Trait {
+                TraitItem(Box::new(Trait {
                     def_id,
                     items,
-                    generics: generics.clean(cx),
-                    bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-                })
+                    generics: clean_generics(generics, cx),
+                    bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+                }))
             }
             ItemKind::ExternCrate(orig_name) => {
                 return clean_extern_crate(item, name, orig_name, cx);
@@ -1969,14 +1973,12 @@ fn clean_maybe_renamed_item<'tcx>(
     })
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::Variant<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let kind = VariantItem(clean_variant_data(&self.data, cx));
-        let what_rustc_thinks =
-            Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
-        // don't show `pub` for variants, which are always public
-        Item { visibility: Inherited, ..what_rustc_thinks }
-    }
+fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
+    let what_rustc_thinks =
+        Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
+    // don't show `pub` for variants, which are always public
+    Item { visibility: Inherited, ..what_rustc_thinks }
 }
 
 fn clean_impl<'tcx>(
@@ -1987,8 +1989,11 @@ fn clean_impl<'tcx>(
     let tcx = cx.tcx;
     let mut ret = Vec::new();
     let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
-    let items =
-        impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+    let items = impl_
+        .items
+        .iter()
+        .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
+        .collect::<Vec<_>>();
     let def_id = tcx.hir().local_def_id(hir_id);
 
     // If this impl block is an implementation of the Deref trait, then we
@@ -2005,7 +2010,7 @@ fn clean_impl<'tcx>(
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Box::new(Impl {
             unsafety: impl_.unsafety,
-            generics: impl_.generics.clean(cx),
+            generics: clean_generics(impl_.generics, cx),
             trait_,
             for_,
             items,
@@ -2106,8 +2111,8 @@ fn clean_use_statement<'tcx>(
     // `pub(super)` or higher. If the current module is the top level
     // module, there isn't really a parent module, which makes the results
     // meaningless. In this case, we make sure the answer is `false`.
-    let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)
-        && !current_mod.is_top_level_module();
+    let is_visible_from_parent_mod =
+        visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module();
 
     if pub_underscore {
         if let Some(ref inline) = inline_attr {
@@ -2202,7 +2207,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
             hir::ForeignItemKind::Fn(decl, names, generics) => {
                 let (generics, decl) = enter_impl_trait(cx, |cx| {
                     // NOTE: generics must be cleaned before args
-                    let generics = generics.clean(cx);
+                    let generics = clean_generics(generics, cx);
                     let args = clean_args_from_types_and_names(cx, decl.inputs, names);
                     let decl = clean_fn_decl_with_args(cx, decl, args);
                     (generics, decl)
@@ -2229,13 +2234,16 @@ fn clean_type_binding<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> TypeBinding {
     TypeBinding {
-        assoc: PathSegment { name: type_binding.ident.name, args: type_binding.gen_args.clean(cx) },
+        assoc: PathSegment {
+            name: type_binding.ident.name,
+            args: clean_generic_args(type_binding.gen_args, cx),
+        },
         kind: match type_binding.kind {
             hir::TypeBindingKind::Equality { ref term } => {
                 TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
             }
             hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
-                bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
+                bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
             },
         },
     }