]> git.proxmox.com Git - rustc.git/blobdiff - src/librustdoc/clean/mod.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / src / librustdoc / clean / mod.rs
index 6e18f381c59a441f6abf3304dcd38930e8e5e795..4fd05c7babdf32a2a93f9f1dcd5ec0861243d0bd 100644 (file)
@@ -3,12 +3,12 @@
 
 mod auto_trait;
 mod blanket_impl;
-crate mod cfg;
-crate mod inline;
+pub(crate) mod cfg;
+pub(crate) mod inline;
 mod render_macro_matchers;
 mod simplify;
-crate mod types;
-crate mod utils;
+pub(crate) mod types;
+pub(crate) mod utils;
 
 use rustc_ast as ast;
 use rustc_attr as attr;
@@ -41,27 +41,57 @@ use crate::visit_ast::Module as DocModule;
 
 use utils::*;
 
-crate use self::types::*;
-crate use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
+pub(crate) use self::types::*;
+pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
 
-crate trait Clean<T> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> T;
+pub(crate) trait Clean<'tcx, T> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
 }
 
-impl Clean<Item> for DocModule<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let mut items: Vec<Item> = vec![];
-        items.extend(
-            self.foreigns
-                .iter()
-                .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
-        );
-        items.extend(self.mods.iter().map(|x| x.clean(cx)));
-        items.extend(
-            self.items
-                .iter()
-                .flat_map(|(item, renamed)| clean_maybe_renamed_item(cx, item, *renamed)),
-        );
+        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 {
+                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.
@@ -89,14 +119,14 @@ impl Clean<Item> for DocModule<'_> {
     }
 }
 
-impl Clean<Attributes> for [ast::Attribute] {
+impl<'tcx> Clean<'tcx, Attributes> for [ast::Attribute] {
     fn clean(&self, _cx: &mut DocContext<'_>) -> Attributes {
         Attributes::from_ast(self, None)
     }
 }
 
-impl Clean<Option<GenericBound>> for hir::GenericBound<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Option<GenericBound> {
+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(lt.clean(cx)),
             hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
@@ -131,9 +161,9 @@ impl Clean<Option<GenericBound>> for hir::GenericBound<'_> {
     }
 }
 
-fn clean_trait_ref_with_bindings(
-    cx: &mut DocContext<'_>,
-    trait_ref: ty::TraitRef<'_>,
+fn clean_trait_ref_with_bindings<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
     bindings: &[TypeBinding],
 ) -> Path {
     let kind = cx.tcx.def_kind(trait_ref.def_id).into();
@@ -148,15 +178,15 @@ fn clean_trait_ref_with_bindings(
     path
 }
 
-impl Clean<Path> for ty::TraitRef<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Path {
+impl<'tcx> Clean<'tcx, Path> for ty::TraitRef<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
         clean_trait_ref_with_bindings(cx, *self, &[])
     }
 }
 
-fn clean_poly_trait_ref_with_bindings(
-    cx: &mut DocContext<'_>,
-    poly_trait_ref: ty::PolyTraitRef<'_>,
+fn clean_poly_trait_ref_with_bindings<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    poly_trait_ref: ty::PolyTraitRef<'tcx>,
     bindings: &[TypeBinding],
 ) -> GenericBound {
     let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
@@ -167,7 +197,7 @@ fn clean_poly_trait_ref_with_bindings(
         .collect_referenced_late_bound_regions(&poly_trait_ref)
         .into_iter()
         .filter_map(|br| match br {
-            ty::BrNamed(_, name) => Some(GenericParamDef {
+            ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(GenericParamDef {
                 name,
                 kind: GenericParamDefKind::Lifetime { outlives: vec![] },
             }),
@@ -182,14 +212,14 @@ fn clean_poly_trait_ref_with_bindings(
     )
 }
 
-impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
+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, &[])
     }
 }
 
-impl Clean<Lifetime> for hir::Lifetime {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
+impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Lifetime {
         let def = cx.tcx.named_region(self.hir_id);
         if let Some(
             rl::Region::EarlyBound(_, node_id)
@@ -205,8 +235,8 @@ impl Clean<Lifetime> for hir::Lifetime {
     }
 }
 
-impl Clean<Constant> for hir::ConstArg {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
+impl<'tcx> Clean<'tcx, Constant> for hir::ConstArg {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant {
         Constant {
             type_: cx
                 .tcx
@@ -217,15 +247,20 @@ impl Clean<Constant> for hir::ConstArg {
     }
 }
 
-impl Clean<Option<Lifetime>> for ty::Region<'_> {
+impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
     fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
         match **self {
             ty::ReStatic => Some(Lifetime::statik()),
             ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
-                Some(Lifetime(name))
+                if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
+            }
+            ty::ReEarlyBound(ref data) => {
+                if data.name != kw::UnderscoreLifetime {
+                    Some(Lifetime(data.name))
+                } else {
+                    None
+                }
             }
-            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
-
             ty::ReLateBound(..)
             | ty::ReFree(..)
             | ty::ReVar(..)
@@ -239,8 +274,8 @@ impl Clean<Option<Lifetime>> for ty::Region<'_> {
     }
 }
 
-impl Clean<Option<WherePredicate>> for hir::WherePredicate<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+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;
         }
@@ -248,7 +283,7 @@ impl Clean<Option<WherePredicate>> for hir::WherePredicate<'_> {
             hir::WherePredicate::BoundPredicate(ref wbp) => {
                 let bound_params = wbp
                     .bound_generic_params
-                    .into_iter()
+                    .iter()
                     .map(|param| {
                         // Higher-ranked params must be lifetimes.
                         // Higher-ranked lifetimes can't have bounds.
@@ -279,8 +314,8 @@ impl Clean<Option<WherePredicate>> for hir::WherePredicate<'_> {
     }
 }
 
-impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+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) => bound_predicate.rebind(pred).clean(cx),
@@ -300,8 +335,8 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
     }
 }
 
-impl<'a> Clean<Option<WherePredicate>> for ty::PolyTraitPredicate<'a> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
         // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
         if self.skip_binder().constness == ty::BoundConstness::ConstIfConst
             && Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
@@ -318,10 +353,10 @@ impl<'a> Clean<Option<WherePredicate>> for ty::PolyTraitPredicate<'a> {
     }
 }
 
-impl<'tcx> Clean<Option<WherePredicate>>
+impl<'tcx> Clean<'tcx, Option<WherePredicate>>
     for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
 {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(a, b) = self;
 
         if a.is_empty() && b.is_empty() {
@@ -335,8 +370,10 @@ impl<'tcx> Clean<Option<WherePredicate>>
     }
 }
 
-impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+impl<'tcx> Clean<'tcx, Option<WherePredicate>>
+    for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>
+{
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(ty, lt) = self;
 
         if lt.is_empty() {
@@ -351,8 +388,8 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
     }
 }
 
-impl<'tcx> Clean<Term> for ty::Term<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
         match self {
             ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
             ty::Term::Const(c) => Term::Constant(c.clean(cx)),
@@ -360,8 +397,8 @@ impl<'tcx> Clean<Term> for ty::Term<'tcx> {
     }
 }
 
-impl<'tcx> Clean<Term> for hir::Term<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
         match self {
             hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
             hir::Term::Const(c) => {
@@ -372,60 +409,72 @@ impl<'tcx> Clean<Term> for hir::Term<'tcx> {
     }
 }
 
-impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
+impl<'tcx> Clean<'tcx, WherePredicate> for ty::ProjectionPredicate<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> WherePredicate {
         let ty::ProjectionPredicate { projection_ty, term } = self;
         WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
     }
 }
 
-impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
-        let lifted = self.lift_to_tcx(cx.tcx).unwrap();
-        let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
-        let self_type = self.self_ty().clean(cx);
-        Type::QPath {
-            assoc: Box::new(projection_to_path_segment(*self, cx)),
-            self_def_id: self_type.def_id(&cx.cache),
-            self_type: box self_type,
-            trait_,
-        }
+fn clean_projection<'tcx>(
+    ty: ty::ProjectionTy<'tcx>,
+    cx: &mut DocContext<'tcx>,
+    def_id: Option<DefId>,
+) -> Type {
+    let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
+    let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
+    let self_type = ty.self_ty().clean(cx);
+    let self_def_id = if let Some(def_id) = def_id {
+        cx.tcx.opt_parent(def_id).or(Some(def_id))
+    } else {
+        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)),
+        should_show_cast,
+        self_type: box self_type,
+        trait_,
     }
 }
 
-fn projection_to_path_segment(ty: ty::ProjectionTy<'_>, cx: &mut DocContext<'_>) -> PathSegment {
+impl<'tcx> Clean<'tcx, Type> for ty::ProjectionTy<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
+        clean_projection(*self, cx, None)
+    }
+}
+
+fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
+    !trait_.segments.is_empty()
+        && self_def_id
+            .zip(Some(trait_.def_id()))
+            .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
+}
+
+fn projection_to_path_segment<'tcx>(
+    ty: ty::ProjectionTy<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> PathSegment {
     let item = cx.tcx.associated_item(ty.item_def_id);
     let generics = cx.tcx.generics_of(ty.item_def_id);
     PathSegment {
         name: item.name,
         args: GenericArgs::AngleBracketed {
-            args: substs_to_args(cx, &ty.substs[generics.parent_count..], false),
+            args: substs_to_args(cx, &ty.substs[generics.parent_count..], false).into(),
             bindings: Default::default(),
         },
     }
 }
 
-impl Clean<GenericParamDef> for ty::GenericParamDef {
-    fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
+impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericParamDef {
         let (name, kind) = match self.kind {
             ty::GenericParamDefKind::Lifetime => {
                 (self.name, GenericParamDefKind::Lifetime { outlives: vec![] })
             }
             ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
                 let default = if has_default {
-                    let mut default = cx.tcx.type_of(self.def_id).clean(cx);
-
-                    // We need to reassign the `self_def_id`, if there's a parent (which is the
-                    // `Self` type), so we can properly render `<Self as X>` casts, because the
-                    // information about which type `Self` is, is only present here, but not in
-                    // the cleaning process of the type itself. To resolve this and have the
-                    // `self_def_id` set, we override it here.
-                    // See https://github.com/rust-lang/rust/issues/85454
-                    if let QPath { ref mut self_def_id, .. } = default {
-                        *self_def_id = Some(cx.tcx.parent(self.def_id));
-                    }
-
-                    Some(default)
+                    Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
                 } else {
                     None
                 };
@@ -456,29 +505,19 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
     }
 }
 
-fn clean_generic_param(
-    cx: &mut DocContext<'_>,
-    generics: Option<&hir::Generics<'_>>,
-    param: &hir::GenericParam<'_>,
+fn clean_generic_param<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    generics: Option<&hir::Generics<'tcx>>,
+    param: &hir::GenericParam<'tcx>,
 ) -> GenericParamDef {
+    let did = cx.tcx.hir().local_def_id(param.hir_id);
     let (name, kind) = match param.kind {
         hir::GenericParamKind::Lifetime { .. } => {
             let outlives = if let Some(generics) = generics {
                 generics
-                    .predicates
-                    .iter()
-                    .flat_map(|pred| {
-                        match pred {
-                            hir::WherePredicate::RegionPredicate(rp)
-                                if rp.lifetime.name == hir::LifetimeName::Param(param.name)
-                                    && !rp.in_where_clause =>
-                            {
-                                rp.bounds
-                            }
-                            _ => &[],
-                        }
-                        .iter()
-                    })
+                    .outlives_for_param(did)
+                    .filter(|bp| !bp.in_where_clause)
+                    .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
                         hir::GenericBound::Outlives(lt) => lt.clean(cx),
                         _ => panic!(),
@@ -490,7 +529,6 @@ fn clean_generic_param(
             (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
         }
         hir::GenericParamKind::Type { ref default, synthetic } => {
-            let did = cx.tcx.hir().local_def_id(param.hir_id);
             let bounds = if let Some(generics) = generics {
                 generics
                     .bounds_for_param(did)
@@ -511,10 +549,10 @@ fn clean_generic_param(
                 },
             )
         }
-        hir::GenericParamKind::Const { ref ty, default } => (
+        hir::GenericParamKind::Const { ty, default } => (
             param.name.ident().name,
             GenericParamDefKind::Const {
-                did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(),
+                did: did.to_def_id(),
                 ty: Box::new(ty.clean(cx)),
                 default: default.map(|ct| {
                     let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
@@ -527,29 +565,25 @@ fn clean_generic_param(
     GenericParamDef { name, kind }
 }
 
-impl Clean<Generics> for hir::Generics<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
-        // Synthetic type-parameters are inserted after normal ones.
-        // In order for normal parameters to be able to refer to synthetic ones,
-        // scans them first.
-        fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
-            match param.kind {
-                hir::GenericParamKind::Type { synthetic, .. } => synthetic,
-                _ => false,
-            }
-        }
-        /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
-        ///
-        /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
-        ///
-        /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
-        fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
-            matches!(
-                param.kind,
-                hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }
-            )
-        }
+/// Synthetic type-parameters are inserted after normal ones.
+/// In order for normal parameters to be able to refer to synthetic ones,
+/// scans them first.
+fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
+    match param.kind {
+        hir::GenericParamKind::Type { synthetic, .. } => synthetic,
+        _ => false,
+    }
+}
 
+/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
+///
+/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
+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()
@@ -609,10 +643,10 @@ impl Clean<Generics> for hir::Generics<'_> {
     }
 }
 
-fn clean_ty_generics(
-    cx: &mut DocContext<'_>,
+fn clean_ty_generics<'tcx>(
+    cx: &mut DocContext<'tcx>,
     gens: &ty::Generics,
-    preds: ty::GenericPredicates<'_>,
+    preds: ty::GenericPredicates<'tcx>,
 ) -> Generics {
     // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
     // since `Clean for ty::Predicate` would consume them.
@@ -775,13 +809,13 @@ fn clean_ty_generics(
     }
 }
 
-fn clean_fn_or_proc_macro(
-    item: &hir::Item<'_>,
-    sig: &hir::FnSig<'_>,
-    generics: &hir::Generics<'_>,
+fn clean_fn_or_proc_macro<'tcx>(
+    item: &hir::Item<'tcx>,
+    sig: &hir::FnSig<'tcx>,
+    generics: &hir::Generics<'tcx>,
     body_id: hir::BodyId,
     name: &mut Symbol,
-    cx: &mut DocContext<'_>,
+    cx: &mut DocContext<'tcx>,
 ) -> ItemKind {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     let macro_kind = attrs.iter().find_map(|a| {
@@ -859,10 +893,10 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
     }
 }
 
-fn clean_function(
-    cx: &mut DocContext<'_>,
-    sig: &hir::FnSig<'_>,
-    generics: &hir::Generics<'_>,
+fn clean_function<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    sig: &hir::FnSig<'tcx>,
+    generics: &hir::Generics<'tcx>,
     body_id: hir::BodyId,
 ) -> Function {
     let (generics, decl) = enter_impl_trait(cx, |cx| {
@@ -875,9 +909,9 @@ fn clean_function(
     Function { decl, generics }
 }
 
-fn clean_args_from_types_and_names(
-    cx: &mut DocContext<'_>,
-    types: &[hir::Ty<'_>],
+fn clean_args_from_types_and_names<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    types: &[hir::Ty<'tcx>],
     names: &[Ident],
 ) -> Arguments {
     Arguments {
@@ -895,9 +929,9 @@ fn clean_args_from_types_and_names(
     }
 }
 
-fn clean_args_from_types_and_body_id(
-    cx: &mut DocContext<'_>,
-    types: &[hir::Ty<'_>],
+fn clean_args_from_types_and_body_id<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    types: &[hir::Ty<'tcx>],
     body_id: hir::BodyId,
 ) -> Arguments {
     let body = cx.tcx.hir().body(body_id);
@@ -915,25 +949,25 @@ fn clean_args_from_types_and_body_id(
     }
 }
 
-fn clean_fn_decl_with_args(
-    cx: &mut DocContext<'_>,
-    decl: &hir::FnDecl<'_>,
+fn clean_fn_decl_with_args<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    decl: &hir::FnDecl<'tcx>,
     args: Arguments,
 ) -> FnDecl {
     FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
 }
 
-fn clean_fn_decl_from_did_and_sig(
-    cx: &mut DocContext<'_>,
+fn clean_fn_decl_from_did_and_sig<'tcx>(
+    cx: &mut DocContext<'tcx>,
     did: Option<DefId>,
-    sig: ty::PolyFnSig<'_>,
+    sig: ty::PolyFnSig<'tcx>,
 ) -> FnDecl {
     let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_names(did)).iter();
 
     // We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
     // but shouldn't change any code meaning.
     let output = match sig.skip_binder().output().clean(cx) {
-        Type::Tuple(inner) if inner.len() == 0 => DefaultReturn,
+        Type::Tuple(inner) if inner.is_empty() => DefaultReturn,
         ty => Return(ty),
     };
 
@@ -955,17 +989,17 @@ fn clean_fn_decl_from_did_and_sig(
     }
 }
 
-impl Clean<FnRetTy> for hir::FnRetTy<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> FnRetTy {
+impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
         match *self {
-            Self::Return(ref typ) => Return(typ.clean(cx)),
+            Self::Return(typ) => Return(typ.clean(cx)),
             Self::DefaultReturn(..) => DefaultReturn,
         }
     }
 }
 
-impl Clean<bool> for hir::IsAuto {
-    fn clean(&self, _: &mut DocContext<'_>) -> bool {
+impl<'tcx> Clean<'tcx, bool> for hir::IsAuto {
+    fn clean(&self, _: &mut DocContext<'tcx>) -> bool {
         match *self {
             hir::IsAuto::Yes => true,
             hir::IsAuto::No => false,
@@ -973,39 +1007,40 @@ impl Clean<bool> for hir::IsAuto {
     }
 }
 
-impl Clean<Path> for hir::TraitRef<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Path {
+impl<'tcx> Clean<'tcx, Path> for hir::TraitRef<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
         let path = self.path.clean(cx);
         register_res(cx, path.res);
         path
     }
 }
 
-impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
+impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait {
         PolyTrait {
             trait_: self.trait_ref.clean(cx),
             generic_params: self
                 .bound_generic_params
                 .iter()
+                .filter(|p| !is_elided_lifetime(p))
                 .map(|x| clean_generic_param(cx, None, x))
                 .collect(),
         }
     }
 }
 
-impl Clean<Item> for hir::TraitItem<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+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(ref ty, Some(default)) => AssocConstItem(
+                hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
                     ty.clean(cx),
                     ConstantKind::Local { def_id: local_did, body: default },
                 ),
-                hir::TraitItemKind::Const(ref ty, None) => TyAssocConstItem(ty.clean(cx)),
+                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(ty.clean(cx)),
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    let m = clean_function(cx, sig, &self.generics, body);
+                    let m = clean_function(cx, sig, self.generics, body);
                     MethodItem(m, None)
                 }
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
@@ -1041,21 +1076,21 @@ impl Clean<Item> for hir::TraitItem<'_> {
     }
 }
 
-impl Clean<Item> for hir::ImplItem<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+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(ref ty, expr) => {
+                hir::ImplItemKind::Const(ty, expr) => {
                     let default = ConstantKind::Local { def_id: local_did, body: expr };
                     AssocConstItem(ty.clean(cx), default)
                 }
                 hir::ImplItemKind::Fn(ref sig, body) => {
-                    let m = clean_function(cx, sig, &self.generics, body);
+                    let m = clean_function(cx, sig, self.generics, body);
                     let defaultness = cx.tcx.associated_item(self.def_id).defaultness;
                     MethodItem(m, Some(defaultness))
                 }
-                hir::ImplItemKind::TyAlias(ref hir_ty) => {
+                hir::ImplItemKind::TyAlias(hir_ty) => {
                     let type_ = hir_ty.clean(cx);
                     let generics = self.generics.clean(cx);
                     let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
@@ -1082,8 +1117,8 @@ impl Clean<Item> for hir::ImplItem<'_> {
     }
 }
 
-impl Clean<Item> for ty::AssocItem {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+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 => {
@@ -1196,7 +1231,7 @@ impl Clean<Item> for ty::AssocItem {
                                             || generics
                                                 .params
                                                 .iter()
-                                                .zip(args)
+                                                .zip(args.iter())
                                                 .any(|(param, arg)| !param_eq_arg(param, arg))
                                         {
                                             return false;
@@ -1273,12 +1308,12 @@ impl Clean<Item> for ty::AssocItem {
     }
 }
 
-fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
+fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
     let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
     let hir::TyKind::Path(qpath) = kind else { unreachable!() };
 
     match qpath {
-        hir::QPath::Resolved(None, ref path) => {
+        hir::QPath::Resolved(None, path) => {
             if let Res::Def(DefKind::TyParam, did) = path.res {
                 if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
                     return new_ty;
@@ -1295,7 +1330,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 resolve_type(cx, path)
             }
         }
-        hir::QPath::Resolved(Some(ref qself), p) => {
+        hir::QPath::Resolved(Some(qself), p) => {
             // Try to normalize `<X as Y>::T` to a type
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             if let Some(normalized_value) = normalize(cx, ty) {
@@ -1309,14 +1344,17 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
             };
             register_res(cx, trait_.res);
+            let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
+            let self_type = qself.clean(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)),
-                self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
-                self_type: box qself.clean(cx),
+                should_show_cast,
+                self_type: box self_type,
                 trait_,
             }
         }
-        hir::QPath::TypeRelative(ref qself, segment) => {
+        hir::QPath::TypeRelative(qself, segment) => {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             let res = match ty.kind() {
                 ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
@@ -1326,10 +1364,13 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
             };
             let trait_ = hir::Path { span, res, segments: &[] }.clean(cx);
             register_res(cx, trait_.res);
+            let self_def_id = res.opt_def_id();
+            let self_type = qself.clean(cx);
+            let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
             Type::QPath {
                 assoc: Box::new(segment.clean(cx)),
-                self_def_id: res.opt_def_id(),
-                self_type: box qself.clean(cx),
+                should_show_cast,
+                self_type: box self_type,
                 trait_,
             }
         }
@@ -1337,7 +1378,10 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
     }
 }
 
-fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option<Type> {
+fn maybe_expand_private_type_alias<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    path: &hir::Path<'tcx>,
+) -> Option<Type> {
     let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
     // Substitute private type aliases
     let def_id = def_id.as_local()?;
@@ -1420,8 +1464,8 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>
     Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
 }
 
-impl Clean<Type> for hir::Ty<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
+impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
         use rustc_hir::*;
 
         match self.kind {
@@ -1436,12 +1480,12 @@ impl Clean<Type> for hir::Ty<'_> {
                 // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
                 // there's no case where it could cause the function to fail to compile.
                 let elided =
-                    l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
+                    l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
                 let lifetime = if elided { None } else { Some(l.clean(cx)) };
                 BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
             }
-            TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
-            TyKind::Array(ref ty, ref length) => {
+            TyKind::Slice(ty) => Slice(box ty.clean(cx)),
+            TyKind::Array(ty, ref length) => {
                 let length = match length {
                     hir::ArrayLen::Infer(_, _) => "_".to_string(),
                     hir::ArrayLen::Body(anon_const) => {
@@ -1476,7 +1520,7 @@ impl Clean<Type> for hir::Ty<'_> {
                 let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
                 DynTrait(bounds, lifetime)
             }
-            TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
+            TyKind::BareFn(barefn) => BareFunction(box barefn.clean(cx)),
             // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
             TyKind::Infer | TyKind::Err => Infer,
             TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
@@ -1515,201 +1559,199 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
     }
 }
 
-impl<'tcx> Clean<Type> for Ty<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
-        trace!("cleaning type: {:?}", self);
-        let ty = normalize(cx, *self).unwrap_or(*self);
-        match *ty.kind() {
-            ty::Never => Primitive(PrimitiveType::Never),
-            ty::Bool => Primitive(PrimitiveType::Bool),
-            ty::Char => Primitive(PrimitiveType::Char),
-            ty::Int(int_ty) => Primitive(int_ty.into()),
-            ty::Uint(uint_ty) => Primitive(uint_ty.into()),
-            ty::Float(float_ty) => Primitive(float_ty.into()),
-            ty::Str => Primitive(PrimitiveType::Str),
-            ty::Slice(ty) => Slice(box ty.clean(cx)),
-            ty::Array(ty, n) => {
-                let mut n = cx.tcx.lift(n).expect("array lift failed");
-                n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
-                let n = print_const(cx, n);
-                Array(box ty.clean(cx), n)
-            }
-            ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)),
-            ty::Ref(r, ty, mutbl) => {
-                BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
-            }
-            ty::FnDef(..) | ty::FnPtr(_) => {
-                let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
-                let sig = ty.fn_sig(cx.tcx);
-                let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
-                BareFunction(box BareFunctionDecl {
-                    unsafety: sig.unsafety(),
-                    generic_params: Vec::new(),
-                    decl,
-                    abi: sig.abi(),
-                })
-            }
-            ty::Adt(def, substs) => {
-                let did = def.did();
-                let kind = match def.adt_kind() {
-                    AdtKind::Struct => ItemType::Struct,
-                    AdtKind::Union => ItemType::Union,
-                    AdtKind::Enum => ItemType::Enum,
-                };
-                inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, did, false, vec![], 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());
-                Type::Path { path }
-            }
-            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()
-                    .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", self));
-                let substs = match obj.principal() {
-                    Some(principal) => principal.skip_binder().substs,
-                    // marker traits have no substs.
-                    _ => cx.tcx.intern_substs(&[]),
-                };
+fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefId>) -> Type {
+    trace!("cleaning type: {:?}", this);
+    let ty = normalize(cx, this).unwrap_or(this);
+    match *ty.kind() {
+        ty::Never => Primitive(PrimitiveType::Never),
+        ty::Bool => Primitive(PrimitiveType::Bool),
+        ty::Char => Primitive(PrimitiveType::Char),
+        ty::Int(int_ty) => Primitive(int_ty.into()),
+        ty::Uint(uint_ty) => Primitive(uint_ty.into()),
+        ty::Float(float_ty) => Primitive(float_ty.into()),
+        ty::Str => Primitive(PrimitiveType::Str),
+        ty::Slice(ty) => Slice(box ty.clean(cx)),
+        ty::Array(ty, n) => {
+            let mut n = cx.tcx.lift(n).expect("array lift failed");
+            n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
+            let n = print_const(cx, n);
+            Array(box ty.clean(cx), n)
+        }
+        ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)),
+        ty::Ref(r, ty, mutbl) => {
+            BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
+        }
+        ty::FnDef(..) | ty::FnPtr(_) => {
+            let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
+            let sig = ty.fn_sig(cx.tcx);
+            let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
+            BareFunction(box BareFunctionDecl {
+                unsafety: sig.unsafety(),
+                generic_params: Vec::new(),
+                decl,
+                abi: sig.abi(),
+            })
+        }
+        ty::Adt(def, substs) => {
+            let did = def.did();
+            let kind = match def.adt_kind() {
+                AdtKind::Struct => ItemType::Struct,
+                AdtKind::Union => ItemType::Union,
+                AdtKind::Enum => ItemType::Enum,
+            };
+            inline::record_extern_fqn(cx, did, kind);
+            let path = external_path(cx, did, false, vec![], 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());
+            Type::Path { path }
+        }
+        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()
+                .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
+            let substs = match obj.principal() {
+                Some(principal) => principal.skip_binder().substs,
+                // marker traits have no substs.
+                _ => cx.tcx.intern_substs(&[]),
+            };
 
-                inline::record_extern_fqn(cx, did, ItemType::Trait);
+            inline::record_extern_fqn(cx, did, ItemType::Trait);
 
-                let lifetime = reg.clean(cx);
-                let mut bounds = vec![];
+            let lifetime = reg.clean(cx);
+            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);
-                }
+            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 bindings = vec![];
-                for pb in obj.projection_bounds() {
-                    bindings.push(TypeBinding {
-                        assoc: projection_to_path_segment(
-                            pb.skip_binder()
-                                .lift_to_tcx(cx.tcx)
-                                .unwrap()
-                                // HACK(compiler-errors): Doesn't actually matter what self
-                                // type we put here, because we're only using the GAT's substs.
-                                .with_self_ty(cx.tcx, cx.tcx.types.self_param)
-                                .projection_ty,
-                            cx,
-                        ),
-                        kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
-                    });
-                }
+            let mut bindings = vec![];
+            for pb in obj.projection_bounds() {
+                bindings.push(TypeBinding {
+                    assoc: projection_to_path_segment(
+                        pb.skip_binder()
+                            .lift_to_tcx(cx.tcx)
+                            .unwrap()
+                            // HACK(compiler-errors): Doesn't actually matter what self
+                            // type we put here, because we're only using the GAT's substs.
+                            .with_self_ty(cx.tcx, cx.tcx.types.self_param)
+                            .projection_ty,
+                        cx,
+                    ),
+                    kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
+                });
+            }
 
-                let path = external_path(cx, did, false, bindings, substs);
-                bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
+            let path = external_path(cx, did, false, bindings, substs);
+            bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
 
-                DynTrait(bounds, lifetime)
-            }
-            ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
+            DynTrait(bounds, lifetime)
+        }
+        ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
 
-            ty::Projection(ref data) => data.clean(cx),
+        ty::Projection(ref data) => clean_projection(*data, cx, def_id),
 
-            ty::Param(ref p) => {
-                if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
-                    ImplTrait(bounds)
-                } else {
-                    Generic(p.name)
-                }
+        ty::Param(ref p) => {
+            if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
+                ImplTrait(bounds)
+            } else {
+                Generic(p.name)
             }
+        }
 
-            ty::Opaque(def_id, substs) => {
-                // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
-                // by looking up the bounds associated with the def_id.
-                let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
-                let bounds = cx
-                    .tcx
-                    .explicit_item_bounds(def_id)
-                    .iter()
-                    .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
-                    .collect::<Vec<_>>();
-                let mut regions = vec![];
-                let mut has_sized = false;
-                let mut bounds = bounds
-                    .iter()
-                    .filter_map(|bound| {
-                        let bound_predicate = bound.kind();
-                        let trait_ref = match bound_predicate.skip_binder() {
-                            ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
-                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
-                                if let Some(r) = reg.clean(cx) {
-                                    regions.push(GenericBound::Outlives(r));
-                                }
-                                return None;
+        ty::Opaque(def_id, substs) => {
+            // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+            // by looking up the bounds associated with the def_id.
+            let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
+            let bounds = cx
+                .tcx
+                .explicit_item_bounds(def_id)
+                .iter()
+                .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
+                .collect::<Vec<_>>();
+            let mut regions = vec![];
+            let mut has_sized = false;
+            let mut bounds = bounds
+                .iter()
+                .filter_map(|bound| {
+                    let bound_predicate = bound.kind();
+                    let trait_ref = match bound_predicate.skip_binder() {
+                        ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
+                        ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
+                            if let Some(r) = reg.clean(cx) {
+                                regions.push(GenericBound::Outlives(r));
                             }
-                            _ => return None,
-                        };
+                            return None;
+                        }
+                        _ => return None,
+                    };
 
-                        if let Some(sized) = cx.tcx.lang_items().sized_trait() {
-                            if trait_ref.def_id() == sized {
-                                has_sized = true;
-                                return None;
-                            }
+                    if let Some(sized) = cx.tcx.lang_items().sized_trait() {
+                        if trait_ref.def_id() == sized {
+                            has_sized = true;
+                            return None;
                         }
+                    }
 
-                        let bindings: Vec<_> = bounds
-                            .iter()
-                            .filter_map(|bound| {
-                                if let ty::PredicateKind::Projection(proj) =
-                                    bound.kind().skip_binder()
-                                {
-                                    if proj.projection_ty.trait_ref(cx.tcx)
-                                        == trait_ref.skip_binder()
-                                    {
-                                        Some(TypeBinding {
-                                            assoc: projection_to_path_segment(
-                                                proj.projection_ty,
-                                                cx,
-                                            ),
-                                            kind: TypeBindingKind::Equality {
-                                                term: proj.term.clean(cx),
-                                            },
-                                        })
-                                    } else {
-                                        None
-                                    }
+                    let bindings: Vec<_> = bounds
+                        .iter()
+                        .filter_map(|bound| {
+                            if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
+                            {
+                                if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
+                                    Some(TypeBinding {
+                                        assoc: projection_to_path_segment(proj.projection_ty, cx),
+                                        kind: TypeBindingKind::Equality {
+                                            term: proj.term.clean(cx),
+                                        },
+                                    })
                                 } else {
                                     None
                                 }
-                            })
-                            .collect();
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
 
-                        Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
-                    })
-                    .collect::<Vec<_>>();
-                bounds.extend(regions);
-                if !has_sized && !bounds.is_empty() {
-                    bounds.insert(0, GenericBound::maybe_sized(cx));
-                }
-                ImplTrait(bounds)
+                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
+                })
+                .collect::<Vec<_>>();
+            bounds.extend(regions);
+            if !has_sized && !bounds.is_empty() {
+                bounds.insert(0, GenericBound::maybe_sized(cx));
             }
+            ImplTrait(bounds)
+        }
 
-            ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
+        ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
 
-            ty::Bound(..) => panic!("Bound"),
-            ty::Placeholder(..) => panic!("Placeholder"),
-            ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
-            ty::Infer(..) => panic!("Infer"),
-            ty::Error(_) => panic!("Error"),
-        }
+        ty::Bound(..) => panic!("Bound"),
+        ty::Placeholder(..) => panic!("Placeholder"),
+        ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
+        ty::Infer(..) => panic!("Infer"),
+        ty::Error(_) => panic!("Error"),
     }
 }
 
-impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
+impl<'tcx> Clean<'tcx, Type> for Ty<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
+        clean_ty(*self, cx, None)
+    }
+}
+
+impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant {
         // FIXME: instead of storing the stringified expression, store `self` directly instead.
         Constant {
             type_: self.ty().clean(cx),
@@ -1718,15 +1760,15 @@ impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
     }
 }
 
-impl Clean<Item> for hir::FieldDef<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+impl<'tcx> Clean<'tcx, Item> for hir::FieldDef<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let def_id = cx.tcx.hir().local_def_id(self.hir_id).to_def_id();
         clean_field(def_id, self.ident.name, self.ty.clean(cx), cx)
     }
 }
 
-impl Clean<Item> for ty::FieldDef {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+impl<'tcx> Clean<'tcx, Item> for ty::FieldDef {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx)
     }
 }
@@ -1752,7 +1794,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-impl Clean<Visibility> for ty::Visibility {
+impl<'tcx> Clean<'tcx, Visibility> for ty::Visibility {
     fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility {
         match *self {
             ty::Visibility::Public => Visibility::Public,
@@ -1766,24 +1808,23 @@ impl Clean<Visibility> for ty::Visibility {
     }
 }
 
-impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> VariantStruct {
+impl<'tcx> Clean<'tcx, VariantStruct> for rustc_hir::VariantData<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> VariantStruct {
         VariantStruct {
             struct_type: CtorKind::from_hir(self),
             fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
-            fields_stripped: false,
         }
     }
 }
 
-impl Clean<Vec<Item>> for hir::VariantData<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
+impl<'tcx> Clean<'tcx, Vec<Item>> for hir::VariantData<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Vec<Item> {
         self.fields().iter().map(|x| x.clean(cx)).collect()
     }
 }
 
-impl Clean<Item> for ty::VariantDef {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+impl<'tcx> Clean<'tcx, Item> for ty::VariantDef {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let kind = match self.ctor_kind {
             CtorKind::Const => Variant::CLike,
             CtorKind::Fn => {
@@ -1791,7 +1832,6 @@ impl Clean<Item> for ty::VariantDef {
             }
             CtorKind::Fictive => Variant::Struct(VariantStruct {
                 struct_type: CtorKind::Fictive,
-                fields_stripped: false,
                 fields: self.fields.iter().map(|field| field.clean(cx)).collect(),
             }),
         };
@@ -1802,8 +1842,8 @@ impl Clean<Item> for ty::VariantDef {
     }
 }
 
-impl Clean<Variant> for hir::VariantData<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Variant {
+impl<'tcx> Clean<'tcx, Variant> for hir::VariantData<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Variant {
         match self {
             hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)),
             hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)),
@@ -1812,19 +1852,19 @@ impl Clean<Variant> for hir::VariantData<'_> {
     }
 }
 
-impl Clean<Path> for hir::Path<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Path {
+impl<'tcx> Clean<'tcx, Path> for hir::Path<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
         Path { res: self.res, segments: self.segments.iter().map(|x| x.clean(cx)).collect() }
     }
 }
 
-impl Clean<GenericArgs> for hir::GenericArgs<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> GenericArgs {
+impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
         if self.parenthesized {
             let output = self.bindings[0].ty().clean(cx);
             let output =
                 if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
-            let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect();
+            let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect::<Vec<_>>().into();
             GenericArgs::Parenthesized { inputs, output }
         } else {
             let args = self
@@ -1839,25 +1879,30 @@ impl Clean<GenericArgs> for hir::GenericArgs<'_> {
                     hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
                     hir::GenericArg::Infer(_inf) => GenericArg::Infer,
                 })
-                .collect();
-            let bindings = self.bindings.iter().map(|x| x.clean(cx)).collect();
+                .collect::<Vec<_>>()
+                .into();
+            let bindings = self.bindings.iter().map(|x| x.clean(cx)).collect::<Vec<_>>().into();
             GenericArgs::AngleBracketed { args, bindings }
         }
     }
 }
 
-impl Clean<PathSegment> for hir::PathSegment<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> PathSegment {
+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) }
     }
 }
 
-impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
+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().map(|x| clean_generic_param(cx, None, x)).collect();
+            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)
@@ -1866,9 +1911,9 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     }
 }
 
-fn clean_maybe_renamed_item(
-    cx: &mut DocContext<'_>,
-    item: &hir::Item<'_>,
+fn clean_maybe_renamed_item<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    item: &hir::Item<'tcx>,
     renamed: Option<Symbol>,
 ) -> Vec<Item> {
     use hir::ItemKind;
@@ -1888,7 +1933,7 @@ fn clean_maybe_renamed_item(
                 bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
                 generics: ty.generics.clean(cx),
             }),
-            ItemKind::TyAlias(hir_ty, ref generics) => {
+            ItemKind::TyAlias(hir_ty, generics) => {
                 let rustdoc_ty = hir_ty.clean(cx);
                 let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
                 TypedefItem(Typedef {
@@ -1897,29 +1942,26 @@ fn clean_maybe_renamed_item(
                     item_type: Some(ty),
                 })
             }
-            ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
+            ItemKind::Enum(ref def, generics) => EnumItem(Enum {
                 variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
                 generics: generics.clean(cx),
-                variants_stripped: false,
             }),
-            ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+            ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
                 generics: generics.clean(cx),
                 bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
             }),
-            ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+            ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
                 generics: generics.clean(cx),
                 fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
-                fields_stripped: false,
             }),
-            ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
+            ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
                 struct_type: CtorKind::from_hir(variant_data),
                 generics: generics.clean(cx),
                 fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
-                fields_stripped: false,
             }),
-            ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
+            ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
             // proc macros can have a name set by attributes
-            ItemKind::Fn(ref sig, ref generics, body_id) => {
+            ItemKind::Fn(ref sig, generics, body_id) => {
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
             }
             ItemKind::Macro(ref macro_def, _) => {
@@ -1928,7 +1970,7 @@ fn clean_maybe_renamed_item(
                     source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
                 })
             }
-            ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
+            ItemKind::Trait(is_auto, unsafety, generics, bounds, item_ids) => {
                 let items =
                     item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
                 TraitItem(Trait {
@@ -1943,7 +1985,7 @@ fn clean_maybe_renamed_item(
                 return clean_extern_crate(item, name, orig_name, cx);
             }
             ItemKind::Use(path, kind) => {
-                return clean_use_statement(item, name, path, kind, cx);
+                return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
             }
             _ => unreachable!("not yet converted"),
         };
@@ -1952,8 +1994,8 @@ fn clean_maybe_renamed_item(
     })
 }
 
-impl Clean<Item> for hir::Variant<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
+impl<'tcx> Clean<'tcx, Item> for hir::Variant<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let kind = VariantItem(self.data.clean(cx));
         let what_rustc_thinks =
             Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
@@ -1962,7 +2004,11 @@ impl Clean<Item> for hir::Variant<'_> {
     }
 }
 
-fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>) -> Vec<Item> {
+fn clean_impl<'tcx>(
+    impl_: &hir::Impl<'tcx>,
+    hir_id: hir::HirId,
+    cx: &mut DocContext<'tcx>,
+) -> Vec<Item> {
     let tcx = cx.tcx;
     let mut ret = Vec::new();
     let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
@@ -1989,7 +2035,11 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
             for_,
             items,
             polarity: tcx.impl_polarity(def_id),
-            kind: ImplKind::Normal,
+            kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::tuple_variadic) {
+                ImplKind::TupleVaradic
+            } else {
+                ImplKind::Normal
+            },
         });
         Item::from_hir_id_and_parts(hir_id, None, kind, cx)
     };
@@ -2000,11 +2050,11 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
     ret
 }
 
-fn clean_extern_crate(
-    krate: &hir::Item<'_>,
+fn clean_extern_crate<'tcx>(
+    krate: &hir::Item<'tcx>,
     name: Symbol,
     orig_name: Option<Symbol>,
-    cx: &mut DocContext<'_>,
+    cx: &mut DocContext<'tcx>,
 ) -> Vec<Item> {
     // this is the ID of the `extern crate` statement
     let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
@@ -2050,12 +2100,13 @@ fn clean_extern_crate(
     }]
 }
 
-fn clean_use_statement(
-    import: &hir::Item<'_>,
+fn clean_use_statement<'tcx>(
+    import: &hir::Item<'tcx>,
     name: Symbol,
-    path: &hir::Path<'_>,
+    path: &hir::Path<'tcx>,
     kind: hir::UseKind,
-    cx: &mut DocContext<'_>,
+    cx: &mut DocContext<'tcx>,
+    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
 ) -> Vec<Item> {
     // We need this comparison because some imports (for std types for example)
     // are "inserted" as well but directly by the compiler and they should not be
@@ -2120,7 +2171,8 @@ fn clean_use_statement(
     let inner = if kind == hir::UseKind::Glob {
         if !denied {
             let mut visited = FxHashSet::default();
-            if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
+            if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
+            {
                 return items;
             }
         }
@@ -2163,15 +2215,15 @@ fn clean_use_statement(
     vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
 }
 
-fn clean_maybe_renamed_foreign_item(
-    cx: &mut DocContext<'_>,
-    item: &hir::ForeignItem<'_>,
+fn clean_maybe_renamed_foreign_item<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    item: &hir::ForeignItem<'tcx>,
     renamed: Option<Symbol>,
 ) -> Item {
     let def_id = item.def_id.to_def_id();
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
-            hir::ForeignItemKind::Fn(decl, names, ref generics) => {
+            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);
@@ -2181,7 +2233,7 @@ fn clean_maybe_renamed_foreign_item(
                 });
                 ForeignFunctionItem(Function { decl, generics })
             }
-            hir::ForeignItemKind::Static(ref ty, mutability) => {
+            hir::ForeignItemKind::Static(ty, mutability) => {
                 ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
             }
             hir::ForeignItemKind::Type => ForeignTypeItem,
@@ -2196,8 +2248,8 @@ fn clean_maybe_renamed_foreign_item(
     })
 }
 
-impl Clean<TypeBinding> for hir::TypeBinding<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding {
+impl<'tcx> Clean<'tcx, TypeBinding> for hir::TypeBinding<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> TypeBinding {
         TypeBinding {
             assoc: PathSegment { name: self.ident.name, args: self.gen_args.clean(cx) },
             kind: self.kind.clean(cx),
@@ -2205,13 +2257,13 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
     }
 }
 
-impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
+impl<'tcx> Clean<'tcx, TypeBindingKind> for hir::TypeBindingKind<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'tcx>) -> TypeBindingKind {
         match *self {
             hir::TypeBindingKind::Equality { ref term } => {
                 TypeBindingKind::Equality { term: term.clean(cx) }
             }
-            hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
+            hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
                 bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
             },
         }