about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2021-03-07 18:09:35 +0100
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2021-03-24 21:48:34 +0100
commit0cde85523f60b8de774bda91d171c9277464d489 (patch)
treebe80e7d44e9c12894f4212bf861c618e1b5c76bd
parentf5fe425c925ef36d5f4c18cfa44173fc42de31b8 (diff)
downloadrust-0cde85523f60b8de774bda91d171c9277464d489.tar.gz
rust-0cde85523f60b8de774bda91d171c9277464d489.zip
Rework rustdoc const type
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/clean/mod.rs23
-rw-r--r--src/librustdoc/clean/types.rs66
-rw-r--r--src/librustdoc/clean/utils.rs24
-rw-r--r--src/librustdoc/html/format.rs717
-rw-r--r--src/librustdoc/html/render/mod.rs96
-rw-r--r--src/librustdoc/html/render/print_item.rs128
-rw-r--r--src/librustdoc/html/render/write_shared.rs2
-rw-r--r--src/librustdoc/json/conversions.rs318
-rw-r--r--src/librustdoc/json/mod.rs10
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs10
11 files changed, 805 insertions, 608 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 0d32c14c3be..223b35634bf 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::Mutability;
 use rustc_metadata::creader::LoadedMacro;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -490,24 +490,17 @@ fn build_module(
     clean::Module { items, is_crate: false }
 }
 
-crate fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String {
+crate fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
     if let Some(did) = did.as_local() {
-        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(did);
-        rustc_hir_pretty::id_to_string(&cx.tcx.hir(), hir_id)
+        let hir_id = tcx.hir().local_def_id_to_hir_id(did);
+        rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id)
     } else {
-        cx.tcx.rendered_const(did)
+        tcx.rendered_const(did)
     }
 }
 
 fn build_const(cx: &mut DocContext<'_>, did: DefId) -> clean::Constant {
-    clean::Constant {
-        type_: cx.tcx.type_of(did).clean(cx),
-        expr: print_inlined_const(cx, did),
-        value: clean::utils::print_evaluated_const(cx, did),
-        is_literal: did.as_local().map_or(false, |did| {
-            clean::utils::is_literal_expr(cx, cx.tcx.hir().local_def_id_to_hir_id(did))
-        }),
-    }
+    clean::Constant::Inline { type_: cx.tcx.type_of(did).clean(cx), did }
 }
 
 fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 84210276d35..6bb8ed60420 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -393,14 +393,12 @@ impl Clean<Lifetime> for hir::GenericParam<'_> {
 
 impl Clean<Constant> for hir::ConstArg {
     fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
-        Constant {
+        Constant::Generic {
             type_: cx
                 .tcx
                 .type_of(cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id())
                 .clean(cx),
-            expr: print_const_expr(cx.tcx, self.value.body),
-            value: None,
-            is_literal: is_literal_expr(cx, self.value.body.hir_id),
+            body: self.value.body,
         }
     }
 }
@@ -1135,7 +1133,7 @@ impl Clean<Item> for ty::AssocItem {
             ty::AssocKind::Const => {
                 let ty = tcx.type_of(self.def_id);
                 let default = if self.defaultness.has_value() {
-                    Some(inline::print_inlined_const(cx, self.def_id))
+                    Some(inline::print_inlined_const(cx.tcx, self.def_id))
                 } else {
                     None
                 };
@@ -1745,12 +1743,8 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
 impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
-        Constant {
-            type_: self.ty.clean(cx),
-            expr: format!("{}", self),
-            value: None,
-            is_literal: false,
-        }
+        // FIXME: instead of storing `format!("{}", self)`, store `self` directly instead.
+        Constant::TyConst { type_: self.ty.clean(cx), expr: format!("{}", self) }
     }
 }
 
@@ -1951,11 +1945,10 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
                 ItemKind::Static(ty, mutability, body_id) => {
                     StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
                 }
-                ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+                ItemKind::Const(ty, body_id) => ConstantItem(Constant::Const {
                     type_: ty.clean(cx),
-                    expr: print_const_expr(cx.tcx, body_id),
-                    value: print_evaluated_const(cx, def_id),
-                    is_literal: is_literal_expr(cx, body_id.hir_id),
+                    body: body_id,
+                    did: def_id,
                 }),
                 ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
                     bounds: ty.bounds.clean(cx),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 142121b7346..bc2588a35f9 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -32,8 +32,9 @@ use rustc_target::spec::abi::Abi;
 
 use crate::clean::cfg::Cfg;
 use crate::clean::external_path;
-use crate::clean::inline;
+use crate::clean::inline::{self, print_inlined_const};
 use crate::clean::types::Type::{QPath, ResolvedPath};
+use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
 use crate::clean::Clean;
 use crate::core::DocContext;
 use crate::formats::cache::Cache;
@@ -1986,11 +1987,64 @@ crate struct Static {
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
-crate struct Constant {
-    crate type_: Type,
-    crate expr: String,
-    crate value: Option<String>,
-    crate is_literal: bool,
+crate enum Constant {
+    /// Typed constant value.
+    TyConst { type_: Type, expr: String },
+    /// A constant (expression) that’s not an item or associated item. These are usually found
+    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
+    /// used to define explicit discriminant values for enum variants.
+    Generic { type_: Type, body: BodyId },
+    /// Inlined constant (from another crate).
+    Inline { type_: Type, did: DefId },
+    /// const FOO: u32 = ...;
+    Const { type_: Type, did: DefId, body: BodyId },
+}
+
+impl Constant {
+    crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
+        match self {
+            Self::TyConst { expr, .. } => expr.clone(),
+            Self::Inline { did, .. } => print_inlined_const(tcx, *did),
+            Self::Const { body, .. } | Self::Generic { body, .. } => print_const_expr(tcx, *body),
+        }
+    }
+
+    crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
+        match self {
+            Self::TyConst { .. } | Self::Generic { .. } => None,
+            Self::Inline { did, .. } | Self::Const { did, .. } => print_evaluated_const(tcx, *did),
+        }
+    }
+
+    crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
+        match self {
+            Self::TyConst { .. } => false,
+            Self::Inline { did, .. } => did
+                .as_local()
+                .map_or(false, |did| is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(did))),
+            Self::Const { body, .. } | Self::Generic { body, .. } => {
+                is_literal_expr(tcx, body.hir_id)
+            }
+        }
+    }
+
+    crate fn type_(&self) -> &Type {
+        match *self {
+            Self::TyConst { ref type_, .. }
+            | Self::Inline { ref type_, .. }
+            | Self::Const { ref type_, .. }
+            | Self::Generic { ref type_, .. } => type_,
+        }
+    }
+
+    crate fn to_type(self) -> Type {
+        match self {
+            Self::TyConst { type_, .. }
+            | Self::Inline { type_, .. }
+            | Self::Const { type_, .. }
+            | Self::Generic { type_, .. } => type_,
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 582cbf69ed1..32bac53e8f5 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -301,7 +301,7 @@ crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
                 let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did);
                 print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id))
             } else {
-                inline::print_inlined_const(cx, def.did)
+                inline::print_inlined_const(cx.tcx, def.did)
             };
             if let Some(promoted) = promoted {
                 s.push_str(&format!("::{:?}", promoted))
@@ -324,15 +324,15 @@ crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
     }
 }
 
-crate fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option<String> {
-    cx.tcx.const_eval_poly(def_id).ok().and_then(|val| {
-        let ty = cx.tcx.type_of(def_id);
+crate fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
+    tcx.const_eval_poly(def_id).ok().and_then(|val| {
+        let ty = tcx.type_of(def_id);
         match (val, ty.kind()) {
             (_, &ty::Ref(..)) => None,
             (ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
             (ConstValue::Scalar(_), _) => {
-                let const_ = ty::Const::from_value(cx.tcx, val, ty);
-                Some(print_const_with_custom_print_scalar(cx, const_))
+                let const_ = ty::Const::from_value(tcx, val, ty);
+                Some(print_const_with_custom_print_scalar(tcx, const_))
             }
             _ => None,
         }
@@ -349,7 +349,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
         .collect()
 }
 
-fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String {
+fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tcx>) -> String {
     // Use a slightly different format for integer types which always shows the actual value.
     // For all other types, fallback to the original `pretty_print_const`.
     match (ct.val, ct.ty.kind()) {
@@ -357,8 +357,8 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
             format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
         }
         (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => {
-            let ty = cx.tcx.lift(ct.ty).unwrap();
-            let size = cx.tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
+            let ty = tcx.lift(ct.ty).unwrap();
+            let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
             let data = int.assert_bits(size);
             let sign_extended_data = size.sign_extend(data) as i128;
 
@@ -372,8 +372,8 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
     }
 }
 
-crate fn is_literal_expr(cx: &DocContext<'_>, hir_id: hir::HirId) -> bool {
-    if let hir::Node::Expr(expr) = cx.tcx.hir().get(hir_id) {
+crate fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
+    if let hir::Node::Expr(expr) = tcx.hir().get(hir_id) {
         if let hir::ExprKind::Lit(_) = &expr.kind {
             return true;
         }
@@ -411,7 +411,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty
             return Generic(kw::SelfUpper);
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
-            return Generic(Symbol::intern(&format!("{:#}", path.print(&cx.cache))));
+            return Generic(Symbol::intern(&format!("{:#}", path.print(&cx.cache, cx.tcx))));
         }
         Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
         _ => false,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 60106f3b7ae..a004ee5054e 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -5,10 +5,10 @@
 //! assume that HTML output is desired, although it may be possible to redesign
 //! them in the future to instead emit any format desired.
 
-use std::borrow::Cow;
 use std::cell::Cell;
 use std::fmt;
 
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_middle::ty::TyCtxt;
@@ -111,31 +111,6 @@ impl Buffer {
     }
 }
 
-/// Wrapper struct for properly emitting a function or method declaration.
-crate struct Function<'a> {
-    /// The declaration to emit.
-    crate decl: &'a clean::FnDecl,
-    /// The length of the function header and name. In other words, the number of characters in the
-    /// function declaration up to but not including the parentheses.
-    ///
-    /// Used to determine line-wrapping.
-    crate header_len: usize,
-    /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
-    crate indent: usize,
-    /// Whether the function is async or not.
-    crate asyncness: hir::IsAsync,
-}
-
-/// Wrapper struct for emitting a where-clause from Generics.
-crate struct WhereClause<'a> {
-    /// The Generics from which to emit a where-clause.
-    crate gens: &'a clean::Generics,
-    /// The number of spaces to indent each line with.
-    crate indent: usize,
-    /// Whether the where-clause needs to add a comma and newline after the last bound.
-    crate end_newline: bool,
-}
-
 fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display {
     display_fn(move |f| {
         for (i, item) in items.enumerate() {
@@ -148,27 +123,32 @@ fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Displ
     })
 }
 
-crate fn print_generic_bounds<'a>(
+crate fn print_generic_bounds<'a, 'tcx: 'a>(
     bounds: &'a [clean::GenericBound],
     cache: &'a Cache,
-) -> impl fmt::Display + 'a {
+    tcx: TyCtxt<'tcx>,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
 
         for (i, bound) in
-            bounds.iter().filter(|b| bounds_dup.insert(b.print(cache).to_string())).enumerate()
+            bounds.iter().filter(|b| bounds_dup.insert(b.print(cache, tcx).to_string())).enumerate()
         {
             if i > 0 {
                 f.write_str(" + ")?;
             }
-            fmt::Display::fmt(&bound.print(cache), f)?;
+            fmt::Display::fmt(&bound.print(cache, tcx), f)?;
         }
         Ok(())
     })
 }
 
 impl clean::GenericParamDef {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self.kind {
             clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
             clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
@@ -176,17 +156,17 @@ impl clean::GenericParamDef {
 
                 if !bounds.is_empty() {
                     if f.alternate() {
-                        write!(f, ": {:#}", print_generic_bounds(bounds, cache))?;
+                        write!(f, ": {:#}", print_generic_bounds(bounds, cache, tcx))?;
                     } else {
-                        write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache))?;
+                        write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache, tcx))?;
                     }
                 }
 
                 if let Some(ref ty) = default {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cache))?;
+                        write!(f, " = {:#}", ty.print(cache, tcx))?;
                     } else {
-                        write!(f, "&nbsp;=&nbsp;{}", ty.print(cache))?;
+                        write!(f, "&nbsp;=&nbsp;{}", ty.print(cache, tcx))?;
                     }
                 }
 
@@ -194,9 +174,9 @@ impl clean::GenericParamDef {
             }
             clean::GenericParamDefKind::Const { ref ty, .. } => {
                 if f.alternate() {
-                    write!(f, "const {}: {:#}", self.name, ty.print(cache))
+                    write!(f, "const {}: {:#}", self.name, ty.print(cache, tcx))
                 } else {
-                    write!(f, "const {}:&nbsp;{}", self.name, ty.print(cache))
+                    write!(f, "const {}:&nbsp;{}", self.name, ty.print(cache, tcx))
                 }
             }
         })
@@ -204,7 +184,11 @@ impl clean::GenericParamDef {
 }
 
 impl clean::Generics {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             let real_params =
                 self.params.iter().filter(|p| !p.is_synthetic_type_param()).collect::<Vec<_>>();
@@ -212,109 +196,115 @@ impl clean::Generics {
                 return Ok(());
             }
             if f.alternate() {
-                write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cache))))
+                write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cache, tcx))))
             } else {
-                write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print(cache))))
+                write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print(cache, tcx))))
             }
         })
     }
 }
 
-impl<'a> WhereClause<'a> {
-    crate fn print<'b>(&'b self, cache: &'b Cache) -> impl fmt::Display + 'b {
-        display_fn(move |f| {
-            let &WhereClause { gens, indent, end_newline } = self;
-            if gens.where_predicates.is_empty() {
-                return Ok(());
+/// * The Generics from which to emit a where-clause.
+/// * The number of spaces to indent each line with.
+/// * Whether the where-clause needs to add a comma and newline after the last bound.
+crate fn print_where_clause<'a, 'tcx: 'a>(
+    gens: &'a clean::Generics,
+    cache: &'a Cache,
+    tcx: TyCtxt<'tcx>,
+    indent: usize,
+    end_newline: bool,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
+    display_fn(move |f| {
+        if gens.where_predicates.is_empty() {
+            return Ok(());
+        }
+        let mut clause = String::new();
+        if f.alternate() {
+            clause.push_str(" where");
+        } else {
+            if end_newline {
+                clause.push_str(" <span class=\"where fmt-newline\">where");
+            } else {
+                clause.push_str(" <span class=\"where\">where");
             }
-            let mut clause = String::new();
+        }
+        for (i, pred) in gens.where_predicates.iter().enumerate() {
             if f.alternate() {
-                clause.push_str(" where");
+                clause.push(' ');
             } else {
-                if end_newline {
-                    clause.push_str(" <span class=\"where fmt-newline\">where");
-                } else {
-                    clause.push_str(" <span class=\"where\">where");
-                }
+                clause.push_str("<br>");
             }
-            for (i, pred) in gens.where_predicates.iter().enumerate() {
-                if f.alternate() {
-                    clause.push(' ');
-                } else {
-                    clause.push_str("<br>");
-                }
 
-                match pred {
-                    clean::WherePredicate::BoundPredicate { ty, bounds } => {
-                        let bounds = bounds;
-                        if f.alternate() {
-                            clause.push_str(&format!(
-                                "{:#}: {:#}",
-                                ty.print(cache),
-                                print_generic_bounds(bounds, cache)
-                            ));
-                        } else {
-                            clause.push_str(&format!(
-                                "{}: {}",
-                                ty.print(cache),
-                                print_generic_bounds(bounds, cache)
-                            ));
-                        }
-                    }
-                    clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+            match pred {
+                clean::WherePredicate::BoundPredicate { ty, bounds } => {
+                    let bounds = bounds;
+                    if f.alternate() {
+                        clause.push_str(&format!(
+                            "{:#}: {:#}",
+                            ty.print(cache, tcx),
+                            print_generic_bounds(bounds, cache, tcx)
+                        ));
+                    } else {
                         clause.push_str(&format!(
                             "{}: {}",
-                            lifetime.print(),
-                            bounds
-                                .iter()
-                                .map(|b| b.print(cache).to_string())
-                                .collect::<Vec<_>>()
-                                .join(" + ")
+                            ty.print(cache, tcx),
+                            print_generic_bounds(bounds, cache, tcx)
                         ));
                     }
-                    clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                        if f.alternate() {
-                            clause.push_str(&format!(
-                                "{:#} == {:#}",
-                                lhs.print(cache),
-                                rhs.print(cache)
-                            ));
-                        } else {
-                            clause.push_str(&format!(
-                                "{} == {}",
-                                lhs.print(cache),
-                                rhs.print(cache)
-                            ));
-                        }
+                }
+                clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+                    clause.push_str(&format!(
+                        "{}: {}",
+                        lifetime.print(),
+                        bounds
+                            .iter()
+                            .map(|b| b.print(cache, tcx).to_string())
+                            .collect::<Vec<_>>()
+                            .join(" + ")
+                    ));
+                }
+                clean::WherePredicate::EqPredicate { lhs, rhs } => {
+                    if f.alternate() {
+                        clause.push_str(&format!(
+                            "{:#} == {:#}",
+                            lhs.print(cache, tcx),
+                            rhs.print(cache, tcx),
+                        ));
+                    } else {
+                        clause.push_str(&format!(
+                            "{} == {}",
+                            lhs.print(cache, tcx),
+                            rhs.print(cache, tcx),
+                        ));
                     }
                 }
+            }
 
-                if i < gens.where_predicates.len() - 1 || end_newline {
-                    clause.push(',');
-                }
+            if i < gens.where_predicates.len() - 1 || end_newline {
+                clause.push(',');
             }
+        }
 
-            if end_newline {
-                // add a space so stripping <br> tags and breaking spaces still renders properly
-                if f.alternate() {
-                    clause.push(' ');
-                } else {
-                    clause.push_str("&nbsp;");
-                }
+        if end_newline {
+            // add a space so stripping <br> tags and breaking spaces still renders properly
+            if f.alternate() {
+                clause.push(' ');
+            } else {
+                clause.push_str("&nbsp;");
             }
+        }
 
-            if !f.alternate() {
-                clause.push_str("</span>");
-                let padding = "&nbsp;".repeat(indent + 4);
-                clause = clause.replace("<br>", &format!("<br>{}", padding));
-                clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
-                if !end_newline {
-                    clause.insert_str(0, "<br>");
-                }
+        if !f.alternate() {
+            clause.push_str("</span>");
+            let padding = "&nbsp;".repeat(indent + 4);
+            clause = clause.replace("<br>", &format!("<br>{}", padding));
+            clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
+            if !end_newline {
+                clause.insert_str(0, "<br>");
             }
-            write!(f, "{}", clause)
-        })
-    }
+        }
+        write!(f, "{}", clause)
+    })
 }
 
 impl clean::Lifetime {
@@ -324,46 +314,53 @@ impl clean::Lifetime {
 }
 
 impl clean::Constant {
-    crate fn print(&self) -> impl fmt::Display + '_ {
-        display_fn(move |f| {
-            if f.alternate() {
-                f.write_str(&self.expr)
-            } else {
-                write!(f, "{}", Escape(&self.expr))
-            }
-        })
+    crate fn print(&self, tcx: TyCtxt<'_>) -> impl fmt::Display + '_ {
+        let expr = self.expr(tcx);
+        display_fn(
+            move |f| {
+                if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
+            },
+        )
     }
 }
 
 impl clean::PolyTrait {
-    fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             if !self.generic_params.is_empty() {
                 if f.alternate() {
                     write!(
                         f,
                         "for<{:#}> ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cache)))
+                        comma_sep(self.generic_params.iter().map(|g| g.print(cache, tcx)))
                     )?;
                 } else {
                     write!(
                         f,
                         "for&lt;{}&gt; ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cache)))
+                        comma_sep(self.generic_params.iter().map(|g| g.print(cache, tcx)))
                     )?;
                 }
             }
             if f.alternate() {
-                write!(f, "{:#}", self.trait_.print(cache))
+                write!(f, "{:#}", self.trait_.print(cache, tcx))
             } else {
-                write!(f, "{}", self.trait_.print(cache))
+                write!(f, "{}", self.trait_.print(cache, tcx))
             }
         })
     }
 }
 
 impl clean::GenericBound {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
             clean::GenericBound::TraitBound(ty, modifier) => {
@@ -373,9 +370,9 @@ impl clean::GenericBound {
                     hir::TraitBoundModifier::MaybeConst => "?const",
                 };
                 if f.alternate() {
-                    write!(f, "{}{:#}", modifier_str, ty.print(cache))
+                    write!(f, "{}{:#}", modifier_str, ty.print(cache, tcx))
                 } else {
-                    write!(f, "{}{}", modifier_str, ty.print(cache))
+                    write!(f, "{}{}", modifier_str, ty.print(cache, tcx))
                 }
             }
         })
@@ -383,7 +380,11 @@ impl clean::GenericBound {
 }
 
 impl clean::GenericArgs {
-    fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             match self {
                 clean::GenericArgs::AngleBracketed { args, bindings } => {
@@ -400,9 +401,9 @@ impl clean::GenericArgs {
                             }
                             comma = true;
                             if f.alternate() {
-                                write!(f, "{:#}", arg.print(cache))?;
+                                write!(f, "{:#}", arg.print(cache, tcx))?;
                             } else {
-                                write!(f, "{}", arg.print(cache))?;
+                                write!(f, "{}", arg.print(cache, tcx))?;
                             }
                         }
                         for binding in bindings {
@@ -411,9 +412,9 @@ impl clean::GenericArgs {
                             }
                             comma = true;
                             if f.alternate() {
-                                write!(f, "{:#}", binding.print(cache))?;
+                                write!(f, "{:#}", binding.print(cache, tcx))?;
                             } else {
-                                write!(f, "{}", binding.print(cache))?;
+                                write!(f, "{}", binding.print(cache, tcx))?;
                             }
                         }
                         if f.alternate() {
@@ -432,17 +433,17 @@ impl clean::GenericArgs {
                         }
                         comma = true;
                         if f.alternate() {
-                            write!(f, "{:#}", ty.print(cache))?;
+                            write!(f, "{:#}", ty.print(cache, tcx))?;
                         } else {
-                            write!(f, "{}", ty.print(cache))?;
+                            write!(f, "{}", ty.print(cache, tcx))?;
                         }
                     }
                     f.write_str(")")?;
                     if let Some(ref ty) = *output {
                         if f.alternate() {
-                            write!(f, " -> {:#}", ty.print(cache))?;
+                            write!(f, " -> {:#}", ty.print(cache, tcx))?;
                         } else {
-                            write!(f, " -&gt; {}", ty.print(cache))?;
+                            write!(f, " -&gt; {}", ty.print(cache, tcx))?;
                         }
                     }
                 }
@@ -453,19 +454,27 @@ impl clean::GenericArgs {
 }
 
 impl clean::PathSegment {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             if f.alternate() {
-                write!(f, "{}{:#}", self.name, self.args.print(cache))
+                write!(f, "{}{:#}", self.name, self.args.print(cache, tcx))
             } else {
-                write!(f, "{}{}", self.name, self.args.print(cache))
+                write!(f, "{}{}", self.name, self.args.print(cache, tcx))
             }
         })
     }
 }
 
 impl clean::Path {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             if self.global {
                 f.write_str("::")?
@@ -476,9 +485,9 @@ impl clean::Path {
                     f.write_str("::")?
                 }
                 if f.alternate() {
-                    write!(f, "{:#}", seg.print(cache))?;
+                    write!(f, "{:#}", seg.print(cache, tcx))?;
                 } else {
-                    write!(f, "{}", seg.print(cache))?;
+                    write!(f, "{}", seg.print(cache, tcx))?;
                 }
             }
             Ok(())
@@ -528,13 +537,14 @@ crate fn href(did: DefId, cache: &Cache) -> Option<(String, ItemType, Vec<String
 
 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
 /// rendering function with the necessary arguments for linking to a local path.
-fn resolved_path(
+fn resolved_path<'a, 'tcx: 'a>(
     w: &mut fmt::Formatter<'_>,
     did: DefId,
     path: &clean::Path,
     print_all: bool,
     use_absolute: bool,
     cache: &Cache,
+    tcx: TyCtxt<'tcx>,
 ) -> fmt::Result {
     let last = path.segments.last().unwrap();
 
@@ -544,7 +554,7 @@ fn resolved_path(
         }
     }
     if w.alternate() {
-        write!(w, "{}{:#}", &last.name, last.args.print(cache))?;
+        write!(w, "{}{:#}", &last.name, last.args.print(cache, tcx))?;
     } else {
         let path = if use_absolute {
             if let Some((_, _, fqp)) = href(did, cache) {
@@ -559,7 +569,7 @@ fn resolved_path(
         } else {
             anchor(did, &*last.name.as_str(), cache).to_string()
         };
-        write!(w, "{}{}", path, last.args.print(cache))?;
+        write!(w, "{}{}", path, last.args.print(cache, tcx))?;
     }
     Ok(())
 }
@@ -615,15 +625,16 @@ fn primitive_link(
 }
 
 /// Helper to render type parameters
-fn tybounds<'a>(
+fn tybounds<'a, 'tcx: 'a>(
     param_names: &'a Option<Vec<clean::GenericBound>>,
     cache: &'a Cache,
-) -> impl fmt::Display + 'a {
+    tcx: TyCtxt<'tcx>,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
     display_fn(move |f| match *param_names {
         Some(ref params) => {
             for param in params {
                 write!(f, " + ")?;
-                fmt::Display::fmt(&param.print(cache), f)?;
+                fmt::Display::fmt(&param.print(cache, tcx), f)?;
             }
             Ok(())
         }
@@ -654,6 +665,7 @@ fn fmt_type(
     f: &mut fmt::Formatter<'_>,
     use_absolute: bool,
     cache: &Cache,
+    tcx: TyCtxt<'_>,
 ) -> fmt::Result {
     debug!("fmt_type(t = {:?})", t);
 
@@ -664,8 +676,8 @@ fn fmt_type(
                 f.write_str("dyn ")?;
             }
             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
-            resolved_path(f, did, path, is_generic, use_absolute, cache)?;
-            fmt::Display::fmt(&tybounds(param_names, cache), f)
+            resolved_path(f, did, path, is_generic, use_absolute, cache, tcx)?;
+            fmt::Display::fmt(&tybounds(param_names, cache, tcx), f)
         }
         clean::Infer => write!(f, "_"),
         clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cache),
@@ -674,21 +686,21 @@ fn fmt_type(
                 write!(
                     f,
                     "{:#}{}{:#}fn{:#}",
-                    decl.print_hrtb_with_space(cache),
+                    decl.print_hrtb_with_space(cache, tcx),
                     decl.unsafety.print_with_space(),
                     print_abi_with_space(decl.abi),
-                    decl.decl.print(cache)
+                    decl.decl.print(cache, tcx),
                 )
             } else {
                 write!(
                     f,
                     "{}{}{}",
-                    decl.print_hrtb_with_space(cache),
+                    decl.print_hrtb_with_space(cache, tcx),
                     decl.unsafety.print_with_space(),
                     print_abi_with_space(decl.abi)
                 )?;
                 primitive_link(f, PrimitiveType::Fn, "fn", cache)?;
-                write!(f, "{}", decl.decl.print(cache))
+                write!(f, "{}", decl.decl.print(cache, tcx))
             }
         }
         clean::Tuple(ref typs) => {
@@ -697,7 +709,7 @@ fn fmt_type(
                 &[ref one] => {
                     primitive_link(f, PrimitiveType::Tuple, "(", cache)?;
                     // Carry `f.alternate()` into this display w/o branching manually.
-                    fmt::Display::fmt(&one.print(cache), f)?;
+                    fmt::Display::fmt(&one.print(cache, tcx), f)?;
                     primitive_link(f, PrimitiveType::Tuple, ",)", cache)
                 }
                 many => {
@@ -706,7 +718,7 @@ fn fmt_type(
                         if i != 0 {
                             write!(f, ", ")?;
                         }
-                        fmt::Display::fmt(&item.print(cache), f)?;
+                        fmt::Display::fmt(&item.print(cache, tcx), f)?;
                     }
                     primitive_link(f, PrimitiveType::Tuple, ")", cache)
                 }
@@ -714,12 +726,12 @@ fn fmt_type(
         }
         clean::Slice(ref t) => {
             primitive_link(f, PrimitiveType::Slice, "[", cache)?;
-            fmt::Display::fmt(&t.print(cache), f)?;
+            fmt::Display::fmt(&t.print(cache, tcx), f)?;
             primitive_link(f, PrimitiveType::Slice, "]", cache)
         }
         clean::Array(ref t, ref n) => {
             primitive_link(f, PrimitiveType::Array, "[", cache)?;
-            fmt::Display::fmt(&t.print(cache), f)?;
+            fmt::Display::fmt(&t.print(cache, tcx), f)?;
             if f.alternate() {
                 primitive_link(f, PrimitiveType::Array, &format!("; {}]", n), cache)
             } else {
@@ -738,14 +750,14 @@ fn fmt_type(
                         primitive_link(
                             f,
                             clean::PrimitiveType::RawPointer,
-                            &format!("*{} {:#}", m, t.print(cache)),
+                            &format!("*{} {:#}", m, t.print(cache, tcx)),
                             cache,
                         )
                     } else {
                         primitive_link(
                             f,
                             clean::PrimitiveType::RawPointer,
-                            &format!("*{} {}", m, t.print(cache)),
+                            &format!("*{} {}", m, t.print(cache, tcx)),
                             cache,
                         )
                     }
@@ -757,7 +769,7 @@ fn fmt_type(
                         &format!("*{} ", m),
                         cache,
                     )?;
-                    fmt::Display::fmt(&t.print(cache), f)
+                    fmt::Display::fmt(&t.print(cache, tcx), f)
                 }
             }
         }
@@ -777,14 +789,14 @@ fn fmt_type(
                                 primitive_link(
                                     f,
                                     PrimitiveType::Slice,
-                                    &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cache)),
+                                    &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cache, tcx)),
                                     cache,
                                 )
                             } else {
                                 primitive_link(
                                     f,
                                     PrimitiveType::Slice,
-                                    &format!("{}{}{}[{}]", amp, lt, m, bt.print(cache)),
+                                    &format!("{}{}{}[{}]", amp, lt, m, bt.print(cache, tcx)),
                                     cache,
                                 )
                             }
@@ -797,9 +809,9 @@ fn fmt_type(
                                 cache,
                             )?;
                             if f.alternate() {
-                                write!(f, "{:#}", bt.print(cache))?;
+                                write!(f, "{:#}", bt.print(cache, tcx))?;
                             } else {
-                                write!(f, "{}", bt.print(cache))?;
+                                write!(f, "{}", bt.print(cache, tcx))?;
                             }
                             primitive_link(f, PrimitiveType::Slice, "]", cache)
                         }
@@ -807,7 +819,7 @@ fn fmt_type(
                 }
                 clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => {
                     write!(f, "{}{}{}(", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute, cache)?;
+                    fmt_type(&ty, f, use_absolute, cache, tcx)?;
                     write!(f, ")")
                 }
                 clean::Generic(..) => {
@@ -817,19 +829,19 @@ fn fmt_type(
                         &format!("{}{}{}", amp, lt, m),
                         cache,
                     )?;
-                    fmt_type(&ty, f, use_absolute, cache)
+                    fmt_type(&ty, f, use_absolute, cache, tcx)
                 }
                 _ => {
                     write!(f, "{}{}{}", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute, cache)
+                    fmt_type(&ty, f, use_absolute, cache, tcx)
                 }
             }
         }
         clean::ImplTrait(ref bounds) => {
             if f.alternate() {
-                write!(f, "impl {:#}", print_generic_bounds(bounds, cache))
+                write!(f, "impl {:#}", print_generic_bounds(bounds, cache, tcx))
             } else {
-                write!(f, "impl {}", print_generic_bounds(bounds, cache))
+                write!(f, "impl {}", print_generic_bounds(bounds, cache, tcx))
             }
         }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
@@ -841,15 +853,25 @@ fn fmt_type(
             };
             if f.alternate() {
                 if should_show_cast {
-                    write!(f, "<{:#} as {:#}>::", self_type.print(cache), trait_.print(cache))?
+                    write!(
+                        f,
+                        "<{:#} as {:#}>::",
+                        self_type.print(cache, tcx),
+                        trait_.print(cache, tcx)
+                    )?
                 } else {
-                    write!(f, "{:#}::", self_type.print(cache))?
+                    write!(f, "{:#}::", self_type.print(cache, tcx))?
                 }
             } else {
                 if should_show_cast {
-                    write!(f, "&lt;{} as {}&gt;::", self_type.print(cache), trait_.print(cache))?
+                    write!(
+                        f,
+                        "&lt;{} as {}&gt;::",
+                        self_type.print(cache, tcx),
+                        trait_.print(cache, tcx)
+                    )?
                 } else {
-                    write!(f, "{}::", self_type.print(cache))?
+                    write!(f, "{}::", self_type.print(cache, tcx))?
                 }
             };
             match *trait_ {
@@ -890,52 +912,64 @@ fn fmt_type(
 }
 
 impl clean::Type {
-    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
-        display_fn(move |f| fmt_type(self, f, false, cache))
+    crate fn print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+        display_fn(move |f| fmt_type(self, f, false, cache, tcx))
     }
 }
 
 impl clean::Impl {
-    crate fn print<'a>(&'a self, cache: &'a Cache, use_absolute: bool) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        use_absolute: bool,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             if f.alternate() {
-                write!(f, "impl{:#} ", self.generics.print(cache))?;
+                write!(f, "impl{:#} ", self.generics.print(cache, tcx))?;
             } else {
-                write!(f, "impl{} ", self.generics.print(cache))?;
+                write!(f, "impl{} ", self.generics.print(cache, tcx))?;
             }
 
             if let Some(ref ty) = self.trait_ {
                 if self.negative_polarity {
                     write!(f, "!")?;
                 }
-                fmt::Display::fmt(&ty.print(cache), f)?;
+                fmt::Display::fmt(&ty.print(cache, tcx), f)?;
                 write!(f, " for ")?;
             }
 
             if let Some(ref ty) = self.blanket_impl {
-                fmt_type(ty, f, use_absolute, cache)?;
+                fmt_type(ty, f, use_absolute, cache, tcx)?;
             } else {
-                fmt_type(&self.for_, f, use_absolute, cache)?;
+                fmt_type(&self.for_, f, use_absolute, cache, tcx)?;
             }
 
-            let where_clause = WhereClause { gens: &self.generics, indent: 0, end_newline: true };
-            fmt::Display::fmt(&where_clause.print(cache), f)?;
+            fmt::Display::fmt(&print_where_clause(&self.generics, cache, tcx, 0, true), f)?;
             Ok(())
         })
     }
 }
 
 impl clean::Arguments {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             for (i, input) in self.values.iter().enumerate() {
                 if !input.name.is_empty() {
                     write!(f, "{}: ", input.name)?;
                 }
                 if f.alternate() {
-                    write!(f, "{:#}", input.type_.print(cache))?;
+                    write!(f, "{:#}", input.type_.print(cache, tcx))?;
                 } else {
-                    write!(f, "{}", input.type_.print(cache))?;
+                    write!(f, "{}", input.type_.print(cache, tcx))?;
                 }
                 if i + 1 < self.values.len() {
                     write!(f, ", ")?;
@@ -947,21 +981,33 @@ impl clean::Arguments {
 }
 
 impl clean::FnRetTy {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()),
-            clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print(cache)),
-            clean::Return(ty) => write!(f, " -&gt; {}", ty.print(cache)),
+            clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print(cache, tcx)),
+            clean::Return(ty) => write!(f, " -&gt; {}", ty.print(cache, tcx)),
             clean::DefaultReturn => Ok(()),
         })
     }
 }
 
 impl clean::BareFunctionDecl {
-    fn print_hrtb_with_space<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    fn print_hrtb_with_space<'a, 'tcx: 'a>(
+        &'a self,
+        cache: &'a Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             if !self.generic_params.is_empty() {
-                write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cache))))
+                write!(
+                    f,
+                    "for<{}> ",
+                    comma_sep(self.generic_params.iter().map(|g| g.print(cache, tcx)))
+                )
             } else {
                 Ok(())
             }
@@ -970,147 +1016,176 @@ impl clean::BareFunctionDecl {
 }
 
 impl clean::FnDecl {
-    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+    crate fn print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
         display_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
                 write!(
                     f,
                     "({args:#}{ellipsis}){arrow:#}",
-                    args = self.inputs.print(cache),
+                    args = self.inputs.print(cache, tcx),
                     ellipsis = ellipsis,
-                    arrow = self.output.print(cache)
+                    arrow = self.output.print(cache, tcx)
                 )
             } else {
                 write!(
                     f,
                     "({args}{ellipsis}){arrow}",
-                    args = self.inputs.print(cache),
+                    args = self.inputs.print(cache, tcx),
                     ellipsis = ellipsis,
-                    arrow = self.output.print(cache)
+                    arrow = self.output.print(cache, tcx)
                 )
             }
         })
     }
-}
 
-impl Function<'_> {
-    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
-        display_fn(move |f| {
-            let &Function { decl, header_len, indent, asyncness } = self;
-            let amp = if f.alternate() { "&" } else { "&amp;" };
-            let mut args = String::new();
-            let mut args_plain = String::new();
-            for (i, input) in decl.inputs.values.iter().enumerate() {
-                if i == 0 {
-                    args.push_str("<br>");
-                }
+    /// * `header_len`: The length of the function header and name. In other words, the number of
+    ///   characters in the function declaration up to but not including the parentheses.
+    ///   <br>Used to determine line-wrapping.
+    /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
+    ///   necessary.
+    /// * `asyncness`: Whether the function is async or not.
+    crate fn full_print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+        header_len: usize,
+        indent: usize,
+        asyncness: hir::IsAsync,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+        display_fn(move |f| self.inner_full_print(cache, tcx, header_len, indent, asyncness, f))
+    }
 
-                if let Some(selfty) = input.to_self() {
-                    match selfty {
-                        clean::SelfValue => {
-                            args.push_str("self");
-                            args_plain.push_str("self");
-                        }
-                        clean::SelfBorrowed(Some(ref lt), mtbl) => {
-                            args.push_str(&format!(
-                                "{}{} {}self",
-                                amp,
-                                lt.print(),
-                                mtbl.print_with_space()
-                            ));
-                            args_plain.push_str(&format!(
-                                "&{} {}self",
-                                lt.print(),
-                                mtbl.print_with_space()
-                            ));
-                        }
-                        clean::SelfBorrowed(None, mtbl) => {
-                            args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
-                            args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
-                        }
-                        clean::SelfExplicit(ref typ) => {
-                            if f.alternate() {
-                                args.push_str(&format!("self: {:#}", typ.print(cache)));
-                            } else {
-                                args.push_str(&format!("self: {}", typ.print(cache)));
-                            }
-                            args_plain.push_str(&format!("self: {:#}", typ.print(cache)));
-                        }
+    fn inner_full_print(
+        &self,
+        cache: &Cache,
+        tcx: TyCtxt<'_>,
+        header_len: usize,
+        indent: usize,
+        asyncness: hir::IsAsync,
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
+        let amp = if f.alternate() { "&" } else { "&amp;" };
+        let mut args = String::new();
+        let mut args_plain = String::new();
+        for (i, input) in self.inputs.values.iter().enumerate() {
+            if i == 0 {
+                args.push_str("<br>");
+            }
+
+            if let Some(selfty) = input.to_self() {
+                match selfty {
+                    clean::SelfValue => {
+                        args.push_str("self");
+                        args_plain.push_str("self");
                     }
-                } else {
-                    if i > 0 {
-                        args.push_str(" <br>");
-                        args_plain.push(' ');
+                    clean::SelfBorrowed(Some(ref lt), mtbl) => {
+                        args.push_str(&format!(
+                            "{}{} {}self",
+                            amp,
+                            lt.print(),
+                            mtbl.print_with_space()
+                        ));
+                        args_plain.push_str(&format!(
+                            "&{} {}self",
+                            lt.print(),
+                            mtbl.print_with_space()
+                        ));
                     }
-                    if !input.name.is_empty() {
-                        args.push_str(&format!("{}: ", input.name));
-                        args_plain.push_str(&format!("{}: ", input.name));
+                    clean::SelfBorrowed(None, mtbl) => {
+                        args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
+                        args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
                     }
-
-                    if f.alternate() {
-                        args.push_str(&format!("{:#}", input.type_.print(cache)));
-                    } else {
-                        args.push_str(&input.type_.print(cache).to_string());
+                    clean::SelfExplicit(ref typ) => {
+                        if f.alternate() {
+                            args.push_str(&format!("self: {:#}", typ.print(cache, tcx)));
+                        } else {
+                            args.push_str(&format!("self: {}", typ.print(cache, tcx)));
+                        }
+                        args_plain.push_str(&format!("self: {:#}", typ.print(cache, tcx)));
                     }
-                    args_plain.push_str(&format!("{:#}", input.type_.print(cache)));
                 }
-                if i + 1 < decl.inputs.values.len() {
-                    args.push(',');
-                    args_plain.push(',');
+            } else {
+                if i > 0 {
+                    args.push_str(" <br>");
+                    args_plain.push(' ');
+                }
+                if !input.name.is_empty() {
+                    args.push_str(&format!("{}: ", input.name));
+                    args_plain.push_str(&format!("{}: ", input.name));
                 }
-            }
-
-            let mut args_plain = format!("({})", args_plain);
 
-            if decl.c_variadic {
-                args.push_str(",<br> ...");
-                args_plain.push_str(", ...");
+                if f.alternate() {
+                    args.push_str(&format!("{:#}", input.type_.print(cache, tcx)));
+                } else {
+                    args.push_str(&input.type_.print(cache, tcx).to_string());
+                }
+                args_plain.push_str(&format!("{:#}", input.type_.print(cache, tcx)));
+            }
+            if i + 1 < self.inputs.values.len() {
+                args.push(',');
+                args_plain.push(',');
             }
+        }
 
-            let output = if let hir::IsAsync::Async = asyncness {
-                Cow::Owned(decl.sugared_async_return_type())
-            } else {
-                Cow::Borrowed(&decl.output)
-            };
+        let mut args_plain = format!("({})", args_plain);
 
-            let arrow_plain = format!("{:#}", &output.print(cache));
-            let arrow = if f.alternate() {
-                format!("{:#}", &output.print(cache))
-            } else {
-                output.print(cache).to_string()
-            };
+        if self.c_variadic {
+            args.push_str(",<br> ...");
+            args_plain.push_str(", ...");
+        }
 
-            let declaration_len = header_len + args_plain.len() + arrow_plain.len();
-            let output = if declaration_len > 80 {
-                let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
-                let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
-                format!(
-                    "({args}{close}){arrow}",
-                    args = args.replace("<br>", &full_pad),
-                    close = close_pad,
-                    arrow = arrow
-                )
+        let arrow_plain;
+        let arrow = if let hir::IsAsync::Async = asyncness {
+            let output = self.sugared_async_return_type();
+            arrow_plain = format!("{:#}", output.print(cache, tcx));
+            if f.alternate() {
+                arrow_plain.clone()
             } else {
-                format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
-            };
-
+                format!("{}", output.print(cache, tcx))
+            }
+        } else {
+            arrow_plain = format!("{:#}", self.output.print(cache, tcx));
             if f.alternate() {
-                write!(f, "{}", output.replace("<br>", "\n"))
+                arrow_plain.clone()
             } else {
-                write!(f, "{}", output)
+                format!("{}", self.output.print(cache, tcx))
             }
-        })
+        };
+
+        let declaration_len = header_len + args_plain.len() + arrow_plain.len();
+        let output = if declaration_len > 80 {
+            let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
+            let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
+            format!(
+                "({args}{close}){arrow}",
+                args = args.replace("<br>", &full_pad),
+                close = close_pad,
+                arrow = arrow
+            )
+        } else {
+            format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
+        };
+
+        if f.alternate() {
+            write!(f, "{}", output.replace("<br>", "\n"))
+        } else {
+            write!(f, "{}", output)
+        }
     }
 }
 
 impl clean::Visibility {
-    crate fn print_with_space<'tcx>(
+    crate fn print_with_space<'a, 'tcx: 'a>(
         self,
         tcx: TyCtxt<'tcx>,
         item_did: DefId,
-        cache: &Cache,
-    ) -> impl fmt::Display + 'tcx {
+        cache: &'a Cache,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
         use rustc_span::symbol::kw;
 
         let to_print = match self {
@@ -1202,20 +1277,24 @@ impl PrintWithSpace for hir::Mutability {
 }
 
 impl clean::Import {
-    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
+    crate fn print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
         display_fn(move |f| match self.kind {
             clean::ImportKind::Simple(name) => {
                 if name == self.source.path.last() {
-                    write!(f, "use {};", self.source.print(cache))
+                    write!(f, "use {};", self.source.print(cache, tcx))
                 } else {
-                    write!(f, "use {} as {};", self.source.print(cache), name)
+                    write!(f, "use {} as {};", self.source.print(cache, tcx), name)
                 }
             }
             clean::ImportKind::Glob => {
                 if self.source.path.segments.is_empty() {
                     write!(f, "use *;")
                 } else {
-                    write!(f, "use {}::*;", self.source.print(cache))
+                    write!(f, "use {}::*;", self.source.print(cache, tcx))
                 }
             }
         })
@@ -1223,9 +1302,13 @@ impl clean::Import {
 }
 
 impl clean::ImportSource {
-    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
+    crate fn print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
         display_fn(move |f| match self.did {
-            Some(did) => resolved_path(f, did, &self.path, true, false, cache),
+            Some(did) => resolved_path(f, did, &self.path, true, false, cache, tcx),
             _ => {
                 for seg in &self.path.segments[..self.path.segments.len() - 1] {
                     write!(f, "{}::", seg.name)?;
@@ -1243,23 +1326,27 @@ impl clean::ImportSource {
 }
 
 impl clean::TypeBinding {
-    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
+    crate fn print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
         display_fn(move |f| {
             f.write_str(&*self.name.as_str())?;
             match self.kind {
                 clean::TypeBindingKind::Equality { ref ty } => {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cache))?;
+                        write!(f, " = {:#}", ty.print(cache, tcx))?;
                     } else {
-                        write!(f, " = {}", ty.print(cache))?;
+                        write!(f, " = {}", ty.print(cache, tcx))?;
                     }
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
                     if !bounds.is_empty() {
                         if f.alternate() {
-                            write!(f, ": {:#}", print_generic_bounds(bounds, cache))?;
+                            write!(f, ": {:#}", print_generic_bounds(bounds, cache, tcx))?;
                         } else {
-                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache))?;
+                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache, tcx))?;
                         }
                     }
                 }
@@ -1284,11 +1371,15 @@ crate fn print_default_space<'a>(v: bool) -> &'a str {
 }
 
 impl clean::GenericArg {
-    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
+    crate fn print<'b, 'a: 'b, 'tcx: 'a>(
+        &'a self,
+        cache: &'b Cache,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl fmt::Display + 'b + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(&lt.print(), f),
-            clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cache), f),
-            clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f),
+            clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cache, tcx), f),
+            clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(tcx), f),
         })
     }
 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 05d30187aa8..25e0be41094 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -67,8 +67,8 @@ use crate::formats::item_type::ItemType;
 use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
-    href, print_abi_with_space, print_default_space, print_generic_bounds, Buffer, Function,
-    PrintWithSpace, WhereClause,
+    href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause,
+    Buffer, PrintWithSpace,
 };
 use crate::html::layout;
 use crate::html::markdown::{self, ErrorCodes, Markdown, MarkdownHtml, MarkdownSummaryLine};
@@ -918,7 +918,7 @@ fn assoc_const(
         it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         naive_assoc_href(it, link, cx.cache()),
         it.name.as_ref().unwrap(),
-        ty.print(cx.cache())
+        ty.print(cx.cache(), cx.tcx())
     );
 }
 
@@ -930,6 +930,7 @@ fn assoc_type(
     link: AssocItemLink<'_>,
     extra: &str,
     cache: &Cache,
+    tcx: TyCtxt<'_>,
 ) {
     write!(
         w,
@@ -939,10 +940,10 @@ fn assoc_type(
         it.name.as_ref().unwrap()
     );
     if !bounds.is_empty() {
-        write!(w, ": {}", print_generic_bounds(bounds, cache))
+        write!(w, ": {}", print_generic_bounds(bounds, cache, tcx))
     }
     if let Some(default) = default {
-        write!(w, " = {}", default.print(cache))
+        write!(w, " = {}", default.print(cache, tcx))
     }
 }
 
@@ -1017,7 +1018,7 @@ fn render_assoc_item(
         let defaultness = print_default_space(meth.is_default());
         let abi = print_abi_with_space(header.abi).to_string();
         // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
-        let generics_len = format!("{:#}", g.print(cx.cache())).len();
+        let generics_len = format!("{:#}", g.print(cx.cache(), tcx)).len();
         let mut header_len = "fn ".len()
             + vis.len()
             + constness.len()
@@ -1049,11 +1050,10 @@ fn render_assoc_item(
             abi,
             href = href,
             name = name,
-            generics = g.print(cx.cache()),
-            decl = Function { decl: d, header_len, indent, asyncness: header.asyncness }
-                .print(cx.cache()),
-            spotlight = spotlight_decl(&d, cx.cache()),
-            where_clause = WhereClause { gens: g, indent, end_newline }.print(cx.cache())
+            generics = g.print(cx.cache(), cx.tcx()),
+            decl = d.full_print(cx.cache(), cx.tcx(), header_len, indent, header.asyncness),
+            spotlight = spotlight_decl(&d, cx.cache(), cx.tcx()),
+            where_clause = print_where_clause(g, cx.cache(), cx.tcx(), indent, end_newline),
         )
     }
     match *item.kind {
@@ -1081,6 +1081,7 @@ fn render_assoc_item(
             link,
             if parent == ItemType::Trait { "    " } else { "" },
             cx.cache(),
+            cx.tcx(),
         ),
         _ => panic!("render_assoc_item called on non-associated-item"),
     }
@@ -1169,9 +1170,9 @@ fn render_assoc_items(
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 let id = cx.derive_id(small_url_encode(format!(
                     "deref-methods-{:#}",
-                    type_.print(cx.cache())
+                    type_.print(cx.cache(), cx.tcx())
                 )));
-                debug!("Adding {} to deref id map", type_.print(cx.cache()));
+                debug!("Adding {} to deref id map", type_.print(cx.cache(), cx.tcx()));
                 cx.deref_id_map
                     .borrow_mut()
                     .insert(type_.def_id_full(cx.cache()).unwrap(), id.clone());
@@ -1182,8 +1183,8 @@ fn render_assoc_items(
                          <a href=\"#{id}\" class=\"anchor\"></a>\
                      </h2>",
                     id = id,
-                    trait_ = trait_.print(cx.cache()),
-                    type_ = type_.print(cx.cache()),
+                    trait_ = trait_.print(cx.cache(), cx.tcx()),
+                    type_ = type_.print(cx.cache(), cx.tcx()),
                 );
                 RenderMode::ForDeref { mut_: deref_mut_ }
             }
@@ -1335,7 +1336,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo
     }
 }
 
-fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String {
+fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache, tcx: TyCtxt<'_>) -> String {
     let mut out = Buffer::html();
     let mut trait_ = String::new();
 
@@ -1351,16 +1352,16 @@ fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String {
                             &mut out,
                             "<h3 class=\"notable\">Notable traits for {}</h3>\
                              <code class=\"content\">",
-                            impl_.for_.print(cache)
+                            impl_.for_.print(cache, tcx)
                         );
-                        trait_.push_str(&impl_.for_.print(cache).to_string());
+                        trait_.push_str(&impl_.for_.print(cache, tcx).to_string());
                     }
 
                     //use the "where" class here to make it small
                     write!(
                         &mut out,
                         "<span class=\"where fmt-newline\">{}</span>",
-                        impl_.print(cache, false)
+                        impl_.print(cache, false, tcx)
                     );
                     let t_did = impl_.trait_.def_id_full(cache).unwrap();
                     for it in &impl_.items {
@@ -1374,6 +1375,7 @@ fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String {
                                 AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
                                 "",
                                 cache,
+                                tcx,
                             );
                             out.push_str(";</span>");
                         }
@@ -1419,9 +1421,12 @@ fn render_impl(
         let id = cx.derive_id(match i.inner_impl().trait_ {
             Some(ref t) => {
                 if is_on_foreign_type {
-                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx.cache())
+                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx.cache(), cx.tcx())
                 } else {
-                    format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx.cache()))))
+                    format!(
+                        "impl-{}",
+                        small_url_encode(format!("{:#}", t.print(cx.cache(), cx.tcx())))
+                    )
                 }
             }
             None => "impl".to_string(),
@@ -1433,7 +1438,7 @@ fn render_impl(
         };
         if let Some(use_absolute) = use_absolute {
             write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases);
-            write!(w, "{}", i.inner_impl().print(cx.cache(), use_absolute));
+            write!(w, "{}", i.inner_impl().print(cx.cache(), use_absolute, cx.tcx()));
             if show_def_docs {
                 for it in &i.inner_impl().items {
                     if let clean::TypedefItem(ref tydef, _) = *it.kind {
@@ -1446,6 +1451,7 @@ fn render_impl(
                             AssocItemLink::Anchor(None),
                             "",
                             cx.cache(),
+                            cx.tcx(),
                         );
                         w.write_str(";</span>");
                     }
@@ -1458,7 +1464,7 @@ fn render_impl(
                 "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
                 id,
                 aliases,
-                i.inner_impl().print(cx.cache(), false)
+                i.inner_impl().print(cx.cache(), false, cx.tcx())
             );
         }
         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -1558,6 +1564,7 @@ fn render_impl(
                     link.anchor(&id),
                     "",
                     cx.cache(),
+                    cx.tcx(),
                 );
                 w.write_str("</code></h4>");
             }
@@ -1579,7 +1586,16 @@ fn render_impl(
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
-                assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "", cx.cache());
+                assoc_type(
+                    w,
+                    item,
+                    bounds,
+                    default.as_ref(),
+                    link.anchor(&id),
+                    "",
+                    cx.cache(),
+                    cx.tcx(),
+                );
                 w.write_str("</code></h4>");
             }
             clean::StrippedItem(..) => return,
@@ -1922,9 +1938,10 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                     .iter()
                     .filter_map(|it| {
                         if let Some(ref i) = it.inner_impl().trait_ {
-                            let i_display = format!("{:#}", i.print(cx.cache()));
+                            let i_display = format!("{:#}", i.print(cx.cache(), cx.tcx()));
                             let out = Escape(&i_display);
-                            let encoded = small_url_encode(format!("{:#}", i.print(cx.cache())));
+                            let encoded =
+                                small_url_encode(format!("{:#}", i.print(cx.cache(), cx.tcx())));
                             let generated = format!(
                                 "<a href=\"#impl-{}\">{}{}</a>",
                                 encoded,
@@ -1988,6 +2005,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
 
 fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
     let c = cx.cache();
+    let tcx = cx.tcx();
 
     debug!("found Deref: {:?}", impl_);
     if let Some((target, real_target)) =
@@ -2036,8 +2054,11 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                     out,
                     "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
                     id,
-                    Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(c))),
-                    Escape(&format!("{:#}", real_target.print(c))),
+                    Escape(&format!(
+                        "{:#}",
+                        impl_.inner_impl().trait_.as_ref().unwrap().print(c, tcx)
+                    )),
+                    Escape(&format!("{:#}", real_target.print(c, tcx))),
                 );
                 // We want links' order to be reproducible so we don't use unstable sort.
                 ret.sort();
@@ -2094,17 +2115,26 @@ fn get_id_for_impl_on_foreign_type(
     for_: &clean::Type,
     trait_: &clean::Type,
     cache: &Cache,
+    tcx: TyCtxt<'_>,
 ) -> String {
-    small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cache), for_.print(cache)))
+    small_url_encode(format!(
+        "impl-{:#}-for-{:#}",
+        trait_.print(cache, tcx),
+        for_.print(cache, tcx)
+    ))
 }
 
-fn extract_for_impl_name(item: &clean::Item, cache: &Cache) -> Option<(String, String)> {
+fn extract_for_impl_name(
+    item: &clean::Item,
+    cache: &Cache,
+    tcx: TyCtxt<'_>,
+) -> Option<(String, String)> {
     match *item.kind {
         clean::ItemKind::ImplItem(ref i) => {
             if let Some(ref trait_) = i.trait_ {
                 Some((
-                    format!("{:#}", i.for_.print(cache)),
-                    get_id_for_impl_on_foreign_type(&i.for_, trait_, cache),
+                    format!("{:#}", i.for_.print(cache, tcx)),
+                    get_id_for_impl_on_foreign_type(&i.for_, trait_, cache, tcx),
                 ))
             } else {
                 None
@@ -2192,7 +2222,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
                     .def_id_full(cx.cache())
                     .map_or(false, |d| !cx.cache.paths.contains_key(&d))
             })
-            .filter_map(|i| extract_for_impl_name(&i.impl_item, cx.cache()))
+            .filter_map(|i| extract_for_impl_name(&i.impl_item, cx.cache(), cx.tcx()))
             .collect::<Vec<_>>();
 
         if !res.is_empty() {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c3c4c4952b3..7662dcf60e3 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -19,7 +19,7 @@ use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode};
 use crate::html::escape::Escape;
-use crate::html::format::{print_abi_with_space, Buffer, Function, PrintWithSpace, WhereClause};
+use crate::html::format::{print_abi_with_space, print_where_clause, Buffer, PrintWithSpace};
 use crate::html::highlight;
 use crate::html::markdown::MarkdownSummaryLine;
 
@@ -266,7 +266,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     w,
                     "<tr><td><code>{}{}</code></td></tr>",
                     myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()),
-                    import.print(cx.cache())
+                    import.print(cx.cache(), cx.tcx()),
                 );
             }
 
@@ -372,7 +372,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         f.header.unsafety.print_with_space(),
         print_abi_with_space(f.header.abi),
         it.name.as_ref().unwrap(),
-        f.generics.print(cx.cache())
+        f.generics.print(cx.cache(), cx.tcx())
     )
     .len();
     w.write_str("<pre class=\"rust fn\">");
@@ -387,18 +387,16 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         unsafety = f.header.unsafety.print_with_space(),
         abi = print_abi_with_space(f.header.abi),
         name = it.name.as_ref().unwrap(),
-        generics = f.generics.print(cx.cache()),
-        where_clause =
-            WhereClause { gens: &f.generics, indent: 0, end_newline: true }.print(cx.cache()),
-        decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness }
-            .print(cx.cache()),
-        spotlight = spotlight_decl(&f.decl, cx.cache()),
+        generics = f.generics.print(cx.cache(), cx.tcx()),
+        where_clause = print_where_clause(&f.generics, cx.cache(), cx.tcx(), 0, true),
+        decl = f.decl.full_print(cx.cache(), cx.tcx(), header_len, 0, f.header.asyncness),
+        spotlight = spotlight_decl(&f.decl, cx.cache(), cx.tcx()),
     );
     document(w, cx, it, None)
 }
 
 fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
-    let bounds = bounds(&t.bounds, false, cx.cache());
+    let bounds = bounds(&t.bounds, false, cx.cache(), cx.tcx());
     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
     let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
@@ -415,13 +413,12 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             t.unsafety.print_with_space(),
             if t.is_auto { "auto " } else { "" },
             it.name.as_ref().unwrap(),
-            t.generics.print(cx.cache()),
+            t.generics.print(cx.cache(), cx.tcx()),
             bounds
         );
 
         if !t.generics.where_predicates.is_empty() {
-            let where_ = WhereClause { gens: &t.generics, indent: 0, end_newline: true };
-            write!(w, "{}", where_.print(cx.cache()));
+            write!(w, "{}", print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true));
         } else {
             w.write_str(" ");
         }
@@ -594,8 +591,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
             local.iter().partition(|i| i.inner_impl().synthetic);
 
-        synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache()));
-        concrete.sort_by(|a, b| compare_impl(a, b, cx.cache()));
+        synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache(), cx.tcx()));
+        concrete.sort_by(|a, b| compare_impl(a, b, cx.cache(), cx.tcx()));
 
         if !foreign.is_empty() {
             write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
@@ -700,9 +697,9 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
         w,
         "trait {}{}{} = {};</pre>",
         it.name.as_ref().unwrap(),
-        t.generics.print(cx.cache()),
-        WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
-        bounds(&t.bounds, true, cx.cache())
+        t.generics.print(cx.cache(), cx.tcx()),
+        print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true),
+        bounds(&t.bounds, true, cx.cache(), cx.tcx())
     );
 
     document(w, cx, it, None);
@@ -721,10 +718,9 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
         w,
         "type {}{}{where_clause} = impl {bounds};</pre>",
         it.name.as_ref().unwrap(),
-        t.generics.print(cx.cache()),
-        where_clause =
-            WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
-        bounds = bounds(&t.bounds, false, cx.cache())
+        t.generics.print(cx.cache(), cx.tcx()),
+        where_clause = print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true),
+        bounds = bounds(&t.bounds, false, cx.cache(), cx.tcx()),
     );
 
     document(w, cx, it, None);
@@ -743,10 +739,9 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
         w,
         "type {}{}{where_clause} = {type_};</pre>",
         it.name.as_ref().unwrap(),
-        t.generics.print(cx.cache()),
-        where_clause =
-            WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
-        type_ = t.type_.print(cx.cache())
+        t.generics.print(cx.cache(), cx.tcx()),
+        where_clause = print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true),
+        type_ = t.type_.print(cx.cache(), cx.tcx()),
     );
 
     document(w, cx, it, None);
@@ -793,7 +788,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
                 id = id,
                 name = name,
                 shortty = ItemType::StructField,
-                ty = ty.print(cx.cache())
+                ty = ty.print(cx.cache(), cx.tcx()),
             );
             if let Some(stability_class) = field.stability_class(cx.tcx()) {
                 write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
@@ -813,8 +808,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             "{}enum {}{}{}",
             it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
             it.name.as_ref().unwrap(),
-            e.generics.print(cx.cache()),
-            WhereClause { gens: &e.generics, indent: 0, end_newline: true }.print(cx.cache())
+            e.generics.print(cx.cache(), cx.tcx()),
+            print_where_clause(&e.generics, cx.cache(), cx.tcx(), 0, true),
         );
         if e.variants.is_empty() && !e.variants_stripped {
             w.write_str(" {}");
@@ -832,7 +827,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                                 if i > 0 {
                                     w.write_str(",&nbsp;")
                                 }
-                                write!(w, "{}", ty.print(cx.cache()));
+                                write!(w, "{}", ty.print(cx.cache(), cx.tcx()));
                             }
                             w.write_str(")");
                         }
@@ -879,7 +874,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                     if i > 0 {
                         w.write_str(",&nbsp;");
                     }
-                    write!(w, "{}", ty.print(cx.cache()));
+                    write!(w, "{}", ty.print(cx.cache(), cx.tcx()));
                 }
                 w.write_str(")");
             }
@@ -916,7 +911,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                              </span>",
                             id = id,
                             f = field.name.as_ref().unwrap(),
-                            t = ty.print(cx.cache())
+                            t = ty.print(cx.cache(), cx.tcx())
                         );
                         document(w, cx, field, Some(variant));
                     }
@@ -987,19 +982,22 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
         "{vis}const {name}: {typ}",
         vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         name = it.name.as_ref().unwrap(),
-        typ = c.type_.print(cx.cache()),
+        typ = c.type_().print(cx.cache(), cx.tcx()),
     );
 
-    if c.value.is_some() || c.is_literal {
-        write!(w, " = {expr};", expr = Escape(&c.expr));
+    let value = c.value(cx.tcx());
+    let is_literal = c.is_literal(cx.tcx());
+    let expr = c.expr(cx.tcx());
+    if value.is_some() || is_literal {
+        write!(w, " = {expr};", expr = Escape(&expr));
     } else {
         w.write_str(";");
     }
 
-    if let Some(value) = &c.value {
-        if !c.is_literal {
+    if !is_literal {
+        if let Some(value) = &value {
             let value_lowercase = value.to_lowercase();
-            let expr_lowercase = c.expr.to_lowercase();
+            let expr_lowercase = expr.to_lowercase();
 
             if value_lowercase != expr_lowercase
                 && value_lowercase.trim_end_matches("i32") != expr_lowercase
@@ -1054,7 +1052,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
                     item_type = ItemType::StructField,
                     id = id,
                     name = field.name.as_ref().unwrap(),
-                    ty = ty.print(cx.cache())
+                    ty = ty.print(cx.cache(), cx.tcx())
                 );
                 document(w, cx, field, Some(it));
             }
@@ -1072,7 +1070,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
         vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         mutability = s.mutability.print_with_space(),
         name = it.name.as_ref().unwrap(),
-        typ = s.type_.print(cx.cache())
+        typ = s.type_.print(cx.cache(), cx.tcx())
     );
     document(w, cx, it, None)
 }
@@ -1147,7 +1145,12 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String {
     }
 }
 
-fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cache: &Cache) -> String {
+fn bounds(
+    t_bounds: &[clean::GenericBound],
+    trait_alias: bool,
+    cache: &Cache,
+    tcx: TyCtxt<'_>,
+) -> String {
     let mut bounds = String::new();
     if !t_bounds.is_empty() {
         if !trait_alias {
@@ -1157,7 +1160,7 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cache: &Cache) ->
             if i > 0 {
                 bounds.push_str(" + ");
             }
-            bounds.push_str(&p.print(cache).to_string());
+            bounds.push_str(&p.print(cache, tcx).to_string());
         }
     }
     bounds
@@ -1187,9 +1190,14 @@ fn render_stability_since(
     )
 }
 
-fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cache: &Cache) -> Ordering {
-    let lhs = format!("{}", lhs.inner_impl().print(cache, false));
-    let rhs = format!("{}", rhs.inner_impl().print(cache, false));
+fn compare_impl<'a, 'b>(
+    lhs: &'a &&Impl,
+    rhs: &'b &&Impl,
+    cache: &Cache,
+    tcx: TyCtxt<'_>,
+) -> Ordering {
+    let lhs = format!("{}", lhs.inner_impl().print(cache, false, tcx));
+    let rhs = format!("{}", rhs.inner_impl().print(cache, false, tcx));
 
     // lhs and rhs are formatted as HTML, which may be unnecessary
     compare_names(&lhs, &rhs)
@@ -1247,8 +1255,8 @@ fn render_union(
         it.name.as_ref().unwrap()
     );
     if let Some(g) = g {
-        write!(w, "{}", g.print(cx.cache()));
-        write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache()));
+        write!(w, "{}", g.print(cx.cache(), cx.tcx()));
+        write!(w, "{}", print_where_clause(&g, cx.cache(), cx.tcx(), 0, true));
     }
 
     write!(w, " {{\n{}", tab);
@@ -1259,7 +1267,7 @@ fn render_union(
                 "    {}{}: {},\n{}",
                 field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
                 field.name.as_ref().unwrap(),
-                ty.print(cx.cache()),
+                ty.print(cx.cache(), cx.tcx()),
                 tab
             );
         }
@@ -1289,16 +1297,12 @@ fn render_struct(
         it.name.as_ref().unwrap()
     );
     if let Some(g) = g {
-        write!(w, "{}", g.print(cx.cache()))
+        write!(w, "{}", g.print(cx.cache(), cx.tcx()))
     }
     match ty {
         CtorKind::Fictive => {
             if let Some(g) = g {
-                write!(
-                    w,
-                    "{}",
-                    WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache())
-                )
+                write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, true),)
             }
             let mut has_visible_fields = false;
             w.write_str(" {");
@@ -1310,7 +1314,7 @@ fn render_struct(
                         tab,
                         field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
                         field.name.as_ref().unwrap(),
-                        ty.print(cx.cache())
+                        ty.print(cx.cache(), cx.tcx()),
                     );
                     has_visible_fields = true;
                 }
@@ -1341,7 +1345,7 @@ fn render_struct(
                             w,
                             "{}{}",
                             field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
-                            ty.print(cx.cache())
+                            ty.print(cx.cache(), cx.tcx()),
                         )
                     }
                     _ => unreachable!(),
@@ -1349,22 +1353,14 @@ fn render_struct(
             }
             w.write_str(")");
             if let Some(g) = g {
-                write!(
-                    w,
-                    "{}",
-                    WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache())
-                )
+                write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, false),)
             }
             w.write_str(";");
         }
         CtorKind::Const => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(
-                    w,
-                    "{}",
-                    WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache())
-                )
+                write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, false),)
             }
             w.write_str(";");
         }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 501d8e8e02e..dc967552116 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -430,7 +430,7 @@ pub(super) fn write_shared(
                     None
                 } else {
                     Some(Implementor {
-                        text: imp.inner_impl().print(cx.cache(), false).to_string(),
+                        text: imp.inner_impl().print(cx.cache(), false, cx.tcx()).to_string(),
                         synthetic: imp.inner_impl().synthetic,
                         types: collect_paths_for_type(imp.inner_impl().for_.clone(), cx.cache()),
                     })
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 073209c2468..110046bebdf 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -27,7 +27,7 @@ impl JsonRenderer<'_> {
         let clean::Item { span, name, attrs, kind, visibility, def_id } = item;
         let inner = match *kind {
             clean::StrippedItem(_) => return None,
-            x => from_clean_item_kind(x, self.tcx, &name),
+            kind => from_clean_item_kind(kind, self.tcx, &name),
         };
         Some(Item {
             id: from_def_id(def_id),
@@ -87,59 +87,78 @@ impl JsonRenderer<'_> {
     }
 }
 
+crate trait FromWithTcx<T> {
+    fn from_tcx(f: T, tcx: TyCtxt<'_>) -> Self;
+}
+
+crate trait IntoWithTcx<T> {
+    fn into_tcx(self, tcx: TyCtxt<'_>) -> T;
+}
+
+impl<T, U> IntoWithTcx<U> for T
+where
+    U: FromWithTcx<T>,
+{
+    fn into_tcx(self, tcx: TyCtxt<'_>) -> U {
+        U::from_tcx(self, tcx)
+    }
+}
+
 crate fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
     #[rustfmt::skip]
     let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
     Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
 }
 
-impl From<clean::GenericArgs> for GenericArgs {
-    fn from(args: clean::GenericArgs) -> Self {
+impl FromWithTcx<clean::GenericArgs> for GenericArgs {
+    fn from_tcx(args: clean::GenericArgs, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericArgs::*;
         match args {
             AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
-                args: args.into_iter().map(Into::into).collect(),
-                bindings: bindings.into_iter().map(Into::into).collect(),
+                args: args.into_iter().map(|a| a.into_tcx(tcx)).collect(),
+                bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(),
             },
             Parenthesized { inputs, output } => GenericArgs::Parenthesized {
-                inputs: inputs.into_iter().map(Into::into).collect(),
-                output: output.map(Into::into),
+                inputs: inputs.into_iter().map(|a| a.into_tcx(tcx)).collect(),
+                output: output.map(|a| a.into_tcx(tcx)),
             },
         }
     }
 }
 
-impl From<clean::GenericArg> for GenericArg {
-    fn from(arg: clean::GenericArg) -> Self {
+impl FromWithTcx<clean::GenericArg> for GenericArg {
+    fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericArg::*;
         match arg {
             Lifetime(l) => GenericArg::Lifetime(l.0.to_string()),
-            Type(t) => GenericArg::Type(t.into()),
-            Const(c) => GenericArg::Const(c.into()),
+            Type(t) => GenericArg::Type(t.into_tcx(tcx)),
+            Const(c) => GenericArg::Const(c.into_tcx(tcx)),
         }
     }
 }
 
-impl From<clean::Constant> for Constant {
-    fn from(constant: clean::Constant) -> Self {
-        let clean::Constant { type_, expr, value, is_literal } = constant;
-        Constant { type_: type_.into(), expr, value, is_literal }
+impl FromWithTcx<clean::Constant> for Constant {
+    fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self {
+        let expr = constant.expr(tcx);
+        let value = constant.value(tcx);
+        let is_literal = constant.is_literal(tcx);
+        Constant { type_: constant.to_type().into_tcx(tcx), expr, value, is_literal }
     }
 }
 
-impl From<clean::TypeBinding> for TypeBinding {
-    fn from(binding: clean::TypeBinding) -> Self {
-        TypeBinding { name: binding.name.to_string(), binding: binding.kind.into() }
+impl FromWithTcx<clean::TypeBinding> for TypeBinding {
+    fn from_tcx(binding: clean::TypeBinding, tcx: TyCtxt<'_>) -> Self {
+        TypeBinding { name: binding.name.to_string(), binding: binding.kind.into_tcx(tcx) }
     }
 }
 
-impl From<clean::TypeBindingKind> for TypeBindingKind {
-    fn from(kind: clean::TypeBindingKind) -> Self {
+impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
+    fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
         use clean::TypeBindingKind::*;
         match kind {
-            Equality { ty } => TypeBindingKind::Equality(ty.into()),
+            Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
             Constraint { bounds } => {
-                TypeBindingKind::Constraint(bounds.into_iter().map(Into::into).collect())
+                TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
             }
         }
     }
@@ -152,32 +171,32 @@ crate fn from_def_id(did: DefId) -> Id {
 fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>, name: &Option<Symbol>) -> ItemEnum {
     use clean::ItemKind::*;
     match item {
-        ModuleItem(m) => ItemEnum::Module(m.into()),
-        ImportItem(i) => ItemEnum::Import(i.into()),
-        StructItem(s) => ItemEnum::Struct(s.into()),
-        UnionItem(u) => ItemEnum::Union(u.into()),
-        StructFieldItem(f) => ItemEnum::StructField(f.into()),
-        EnumItem(e) => ItemEnum::Enum(e.into()),
-        VariantItem(v) => ItemEnum::Variant(v.into()),
-        FunctionItem(f) => ItemEnum::Function(f.into()),
-        ForeignFunctionItem(f) => ItemEnum::Function(f.into()),
-        TraitItem(t) => ItemEnum::Trait(t.into()),
-        TraitAliasItem(t) => ItemEnum::TraitAlias(t.into()),
-        MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true)),
-        TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false)),
-        ImplItem(i) => ItemEnum::Impl(i.into()),
-        StaticItem(s) => ItemEnum::Static(from_clean_static(s, tcx)),
-        ForeignStaticItem(s) => ItemEnum::Static(from_clean_static(s, tcx)),
+        ModuleItem(m) => ItemEnum::Module(m.into_tcx(tcx)),
+        ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
+        StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
+        UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
+        StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)),
+        EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)),
+        VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)),
+        FunctionItem(f) => ItemEnum::Function(f.into_tcx(tcx)),
+        ForeignFunctionItem(f) => ItemEnum::Function(f.into_tcx(tcx)),
+        TraitItem(t) => ItemEnum::Trait(t.into_tcx(tcx)),
+        TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
+        MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, tcx)),
+        TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, tcx)),
+        ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)),
+        StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
+        ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
         ForeignTypeItem => ItemEnum::ForeignType,
-        TypedefItem(t, _) => ItemEnum::Typedef(t.into()),
-        OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into()),
-        ConstantItem(c) => ItemEnum::Constant(c.into()),
+        TypedefItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)),
+        OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)),
+        ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)),
         MacroItem(m) => ItemEnum::Macro(m.source),
-        ProcMacroItem(m) => ItemEnum::ProcMacro(m.into()),
-        AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into(), default: s },
+        ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
+        AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into_tcx(tcx), default: s },
         AssocTypeItem(g, t) => ItemEnum::AssocType {
-            bounds: g.into_iter().map(Into::into).collect(),
-            default: t.map(Into::into),
+            bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            default: t.map(|x| x.into_tcx(tcx)),
         },
         StrippedItem(inner) => from_clean_item_kind(*inner, tcx, name),
         PrimitiveItem(_) | KeywordItem(_) => {
@@ -190,18 +209,18 @@ fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>, name: &Option<Sy
     }
 }
 
-impl From<clean::Module> for Module {
-    fn from(module: clean::Module) -> Self {
+impl FromWithTcx<clean::Module> for Module {
+    fn from_tcx(module: clean::Module, _tcx: TyCtxt<'_>) -> Self {
         Module { is_crate: module.is_crate, items: ids(module.items) }
     }
 }
 
-impl From<clean::Struct> for Struct {
-    fn from(struct_: clean::Struct) -> Self {
+impl FromWithTcx<clean::Struct> for Struct {
+    fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
         let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_;
         Struct {
             struct_type: from_ctor_kind(struct_type),
-            generics: generics.into(),
+            generics: generics.into_tcx(tcx),
             fields_stripped,
             fields: ids(fields),
             impls: Vec::new(), // Added in JsonRenderer::item
@@ -209,11 +228,11 @@ impl From<clean::Struct> for Struct {
     }
 }
 
-impl From<clean::Union> for Union {
-    fn from(struct_: clean::Union) -> Self {
+impl FromWithTcx<clean::Union> for Union {
+    fn from_tcx(struct_: clean::Union, tcx: TyCtxt<'_>) -> Self {
         let clean::Union { generics, fields, fields_stripped } = struct_;
         Union {
-            generics: generics.into(),
+            generics: generics.into_tcx(tcx),
             fields_stripped,
             fields: ids(fields),
             impls: Vec::new(), // Added in JsonRenderer::item
@@ -247,74 +266,81 @@ crate fn from_fn_header(header: &rustc_hir::FnHeader) -> HashSet<Qualifiers> {
     v
 }
 
-impl From<clean::Function> for Function {
-    fn from(function: clean::Function) -> Self {
+impl FromWithTcx<clean::Function> for Function {
+    fn from_tcx(function: clean::Function, tcx: TyCtxt<'_>) -> Self {
         let clean::Function { decl, generics, header } = function;
         Function {
-            decl: decl.into(),
-            generics: generics.into(),
+            decl: decl.into_tcx(tcx),
+            generics: generics.into_tcx(tcx),
             header: from_fn_header(&header),
             abi: header.abi.to_string(),
         }
     }
 }
 
-impl From<clean::Generics> for Generics {
-    fn from(generics: clean::Generics) -> Self {
+impl FromWithTcx<clean::Generics> for Generics {
+    fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
         Generics {
-            params: generics.params.into_iter().map(Into::into).collect(),
-            where_predicates: generics.where_predicates.into_iter().map(Into::into).collect(),
+            params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            where_predicates: generics
+                .where_predicates
+                .into_iter()
+                .map(|x| x.into_tcx(tcx))
+                .collect(),
         }
     }
 }
 
-impl From<clean::GenericParamDef> for GenericParamDef {
-    fn from(generic_param: clean::GenericParamDef) -> Self {
-        GenericParamDef { name: generic_param.name.to_string(), kind: generic_param.kind.into() }
+impl FromWithTcx<clean::GenericParamDef> for GenericParamDef {
+    fn from_tcx(generic_param: clean::GenericParamDef, tcx: TyCtxt<'_>) -> Self {
+        GenericParamDef {
+            name: generic_param.name.to_string(),
+            kind: generic_param.kind.into_tcx(tcx),
+        }
     }
 }
 
-impl From<clean::GenericParamDefKind> for GenericParamDefKind {
-    fn from(kind: clean::GenericParamDefKind) -> Self {
+impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
+    fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericParamDefKind::*;
         match kind {
             Lifetime => GenericParamDefKind::Lifetime,
             Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
-                bounds: bounds.into_iter().map(Into::into).collect(),
-                default: default.map(Into::into),
+                bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+                default: default.map(|x| x.into_tcx(tcx)),
             },
-            Const { did: _, ty } => GenericParamDefKind::Const(ty.into()),
+            Const { did: _, ty } => GenericParamDefKind::Const(ty.into_tcx(tcx)),
         }
     }
 }
 
-impl From<clean::WherePredicate> for WherePredicate {
-    fn from(predicate: clean::WherePredicate) -> Self {
+impl FromWithTcx<clean::WherePredicate> for WherePredicate {
+    fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
         use clean::WherePredicate::*;
         match predicate {
             BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate {
-                ty: ty.into(),
-                bounds: bounds.into_iter().map(Into::into).collect(),
+                ty: ty.into_tcx(tcx),
+                bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             },
             RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
                 lifetime: lifetime.0.to_string(),
-                bounds: bounds.into_iter().map(Into::into).collect(),
+                bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             },
             EqPredicate { lhs, rhs } => {
-                WherePredicate::EqPredicate { lhs: lhs.into(), rhs: rhs.into() }
+                WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
             }
         }
     }
 }
 
-impl From<clean::GenericBound> for GenericBound {
-    fn from(bound: clean::GenericBound) -> Self {
+impl FromWithTcx<clean::GenericBound> for GenericBound {
+    fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericBound::*;
         match bound {
             TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
                 GenericBound::TraitBound {
-                    trait_: trait_.into(),
-                    generic_params: generic_params.into_iter().map(Into::into).collect(),
+                    trait_: trait_.into_tcx(tcx),
+                    generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
                     modifier: from_trait_bound_modifier(modifier),
                 }
             }
@@ -332,47 +358,47 @@ crate fn from_trait_bound_modifier(modifier: rustc_hir::TraitBoundModifier) -> T
     }
 }
 
-impl From<clean::Type> for Type {
-    fn from(ty: clean::Type) -> Self {
+impl FromWithTcx<clean::Type> for Type {
+    fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         use clean::Type::*;
         match ty {
             ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
                 name: path.whole_name(),
                 id: from_def_id(did),
-                args: path.segments.last().map(|args| Box::new(args.clone().args.into())),
+                args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: param_names
-                    .map(|v| v.into_iter().map(Into::into).collect())
+                    .map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
                     .unwrap_or_default(),
             },
             Generic(s) => Type::Generic(s.to_string()),
             Primitive(p) => Type::Primitive(p.as_str().to_string()),
-            BareFunction(f) => Type::FunctionPointer(Box::new((*f).into())),
-            Tuple(t) => Type::Tuple(t.into_iter().map(Into::into).collect()),
-            Slice(t) => Type::Slice(Box::new((*t).into())),
-            Array(t, s) => Type::Array { type_: Box::new((*t).into()), len: s },
-            ImplTrait(g) => Type::ImplTrait(g.into_iter().map(Into::into).collect()),
+            BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
+            Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
+            Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
+            Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
+            ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()),
             Never => Type::Never,
             Infer => Type::Infer,
             RawPointer(mutability, type_) => Type::RawPointer {
                 mutable: mutability == ast::Mutability::Mut,
-                type_: Box::new((*type_).into()),
+                type_: Box::new((*type_).into_tcx(tcx)),
             },
             BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
                 lifetime: lifetime.map(|l| l.0.to_string()),
                 mutable: mutability == ast::Mutability::Mut,
-                type_: Box::new((*type_).into()),
+                type_: Box::new((*type_).into_tcx(tcx)),
             },
             QPath { name, self_type, trait_ } => Type::QualifiedPath {
                 name: name.to_string(),
-                self_type: Box::new((*self_type).into()),
-                trait_: Box::new((*trait_).into()),
+                self_type: Box::new((*self_type).into_tcx(tcx)),
+                trait_: Box::new((*trait_).into_tcx(tcx)),
             },
         }
     }
 }
 
-impl From<clean::BareFunctionDecl> for FunctionPointer {
-    fn from(bare_decl: clean::BareFunctionDecl) -> Self {
+impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
+    fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
         let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
         FunctionPointer {
             header: if let rustc_hir::Unsafety::Unsafe = unsafety {
@@ -382,24 +408,24 @@ impl From<clean::BareFunctionDecl> for FunctionPointer {
             } else {
                 HashSet::new()
             },
-            generic_params: generic_params.into_iter().map(Into::into).collect(),
-            decl: decl.into(),
+            generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            decl: decl.into_tcx(tcx),
             abi: abi.to_string(),
         }
     }
 }
 
-impl From<clean::FnDecl> for FnDecl {
-    fn from(decl: clean::FnDecl) -> Self {
+impl FromWithTcx<clean::FnDecl> for FnDecl {
+    fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self {
         let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl;
         FnDecl {
             inputs: inputs
                 .values
                 .into_iter()
-                .map(|arg| (arg.name.to_string(), arg.type_.into()))
+                .map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx)))
                 .collect(),
             output: match output {
-                clean::FnRetTy::Return(t) => Some(t.into()),
+                clean::FnRetTy::Return(t) => Some(t.into_tcx(tcx)),
                 clean::FnRetTy::DefaultReturn => None,
             },
             c_variadic,
@@ -407,22 +433,22 @@ impl From<clean::FnDecl> for FnDecl {
     }
 }
 
-impl From<clean::Trait> for Trait {
-    fn from(trait_: clean::Trait) -> Self {
+impl FromWithTcx<clean::Trait> for Trait {
+    fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
         let clean::Trait { unsafety, items, generics, bounds, is_auto } = trait_;
         Trait {
             is_auto,
             is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
             items: ids(items),
-            generics: generics.into(),
-            bounds: bounds.into_iter().map(Into::into).collect(),
+            generics: generics.into_tcx(tcx),
+            bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             implementors: Vec::new(), // Added in JsonRenderer::item
         }
     }
 }
 
-impl From<clean::Impl> for Impl {
-    fn from(impl_: clean::Impl) -> Self {
+impl FromWithTcx<clean::Impl> for Impl {
+    fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
         let clean::Impl {
             unsafety,
             generics,
@@ -436,37 +462,41 @@ impl From<clean::Impl> for Impl {
         } = impl_;
         Impl {
             is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
-            generics: generics.into(),
+            generics: generics.into_tcx(tcx),
             provided_trait_methods: provided_trait_methods
                 .into_iter()
                 .map(|x| x.to_string())
                 .collect(),
-            trait_: trait_.map(Into::into),
-            for_: for_.into(),
+            trait_: trait_.map(|x| x.into_tcx(tcx)),
+            for_: for_.into_tcx(tcx),
             items: ids(items),
             negative: negative_polarity,
             synthetic,
-            blanket_impl: blanket_impl.map(Into::into),
+            blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
         }
     }
 }
 
-crate fn from_function_method(function: clean::Function, has_body: bool) -> Method {
+crate fn from_function_method(
+    function: clean::Function,
+    has_body: bool,
+    tcx: TyCtxt<'_>,
+) -> Method {
     let clean::Function { header, decl, generics } = function;
     Method {
-        decl: decl.into(),
-        generics: generics.into(),
+        decl: decl.into_tcx(tcx),
+        generics: generics.into_tcx(tcx),
         header: from_fn_header(&header),
         abi: header.abi.to_string(),
         has_body,
     }
 }
 
-impl From<clean::Enum> for Enum {
-    fn from(enum_: clean::Enum) -> Self {
+impl FromWithTcx<clean::Enum> for Enum {
+    fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
         let clean::Enum { variants, generics, variants_stripped } = enum_;
         Enum {
-            generics: generics.into(),
+            generics: generics.into_tcx(tcx),
             variants_stripped,
             variants: ids(variants),
             impls: Vec::new(), // Added in JsonRenderer::item
@@ -474,8 +504,8 @@ impl From<clean::Enum> for Enum {
     }
 }
 
-impl From<clean::VariantStruct> for Struct {
-    fn from(struct_: clean::VariantStruct) -> Self {
+impl FromWithTcx<clean::VariantStruct> for Struct {
+    fn from_tcx(struct_: clean::VariantStruct, _tcx: TyCtxt<'_>) -> Self {
         let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_;
         Struct {
             struct_type: from_ctor_kind(struct_type),
@@ -487,19 +517,19 @@ impl From<clean::VariantStruct> for Struct {
     }
 }
 
-impl From<clean::Variant> for Variant {
-    fn from(variant: clean::Variant) -> Self {
+impl FromWithTcx<clean::Variant> for Variant {
+    fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
         use clean::Variant::*;
         match variant {
             CLike => Variant::Plain,
-            Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()),
+            Tuple(t) => Variant::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
             Struct(s) => Variant::Struct(ids(s.fields)),
         }
     }
 }
 
-impl From<clean::Import> for Import {
-    fn from(import: clean::Import) -> Self {
+impl FromWithTcx<clean::Import> for Import {
+    fn from_tcx(import: clean::Import, _tcx: TyCtxt<'_>) -> Self {
         use clean::ImportKind::*;
         match import.kind {
             Simple(s) => Import {
@@ -518,8 +548,8 @@ impl From<clean::Import> for Import {
     }
 }
 
-impl From<clean::ProcMacro> for ProcMacro {
-    fn from(mac: clean::ProcMacro) -> Self {
+impl FromWithTcx<clean::ProcMacro> for ProcMacro {
+    fn from_tcx(mac: clean::ProcMacro, _tcx: TyCtxt<'_>) -> Self {
         ProcMacro {
             kind: from_macro_kind(mac.kind),
             helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
@@ -536,41 +566,43 @@ crate fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind {
     }
 }
 
-impl From<clean::Typedef> for Typedef {
-    fn from(typedef: clean::Typedef) -> Self {
+impl FromWithTcx<clean::Typedef> for Typedef {
+    fn from_tcx(typedef: clean::Typedef, tcx: TyCtxt<'_>) -> Self {
         let clean::Typedef { type_, generics, item_type: _ } = typedef;
-        Typedef { type_: type_.into(), generics: generics.into() }
+        Typedef { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) }
     }
 }
 
-impl From<clean::OpaqueTy> for OpaqueTy {
-    fn from(opaque: clean::OpaqueTy) -> Self {
+impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
+    fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
         OpaqueTy {
-            bounds: opaque.bounds.into_iter().map(Into::into).collect(),
-            generics: opaque.generics.into(),
+            bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            generics: opaque.generics.into_tcx(tcx),
         }
     }
 }
 
-fn from_clean_static(stat: clean::Static, tcx: TyCtxt<'_>) -> Static {
-    Static {
-        type_: stat.type_.into(),
-        mutable: stat.mutability == ast::Mutability::Mut,
-        expr: stat.expr.map(|e| print_const_expr(tcx, e)).unwrap_or_default(),
+impl FromWithTcx<clean::Static> for Static {
+    fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self {
+        Static {
+            type_: stat.type_.into_tcx(tcx),
+            mutable: stat.mutability == ast::Mutability::Mut,
+            expr: stat.expr.map(|e| print_const_expr(tcx, e)).unwrap_or_default(),
+        }
     }
 }
 
-impl From<clean::TraitAlias> for TraitAlias {
-    fn from(alias: clean::TraitAlias) -> Self {
+impl FromWithTcx<clean::TraitAlias> for TraitAlias {
+    fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
         TraitAlias {
-            generics: alias.generics.into(),
-            params: alias.bounds.into_iter().map(Into::into).collect(),
+            generics: alias.generics.into_tcx(tcx),
+            params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
         }
     }
 }
 
-impl From<ItemType> for ItemKind {
-    fn from(kind: ItemType) -> Self {
+impl FromWithTcx<ItemType> for ItemKind {
+    fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self {
         use ItemType::*;
         match kind {
             Module => ItemKind::Module,
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index a4cdad69865..6d18dbe67e4 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -24,7 +24,7 @@ use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
 use crate::html::render::cache::ExternalLocation;
-use crate::json::conversions::from_def_id;
+use crate::json::conversions::{from_def_id, IntoWithTcx};
 
 #[derive(Clone)]
 crate struct JsonRenderer<'tcx> {
@@ -108,7 +108,7 @@ impl JsonRenderer<'tcx> {
                                 .last()
                                 .map(Clone::clone),
                             visibility: types::Visibility::Public,
-                            inner: types::ItemEnum::Trait(trait_item.clone().into()),
+                            inner: types::ItemEnum::Trait(trait_item.clone().into_tcx(self.tcx)),
                             span: None,
                             docs: Default::default(),
                             links: Default::default(),
@@ -225,7 +225,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .map(|(k, (path, kind))| {
                     (
                         from_def_id(k),
-                        types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() },
+                        types::ItemSummary {
+                            crate_id: k.krate.as_u32(),
+                            path,
+                            kind: kind.into_tcx(self.tcx),
+                        },
                     )
                 })
                 .collect(),
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index a2f8eb3772e..ad269413ac6 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -216,8 +216,8 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
                 if let Some(ref tr) = impl_.trait_ {
                     debug!(
                         "impl {:#} for {:#} in {}",
-                        tr.print(&self.ctx.cache),
-                        impl_.for_.print(&self.ctx.cache),
+                        tr.print(&self.ctx.cache, self.ctx.tcx),
+                        impl_.for_.print(&self.ctx.cache, self.ctx.tcx),
                         filename,
                     );
 
@@ -228,7 +228,11 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
                     // inherent impls *can* be documented, and those docs show up, but in most
                     // cases it doesn't make sense, as all methods on a type are in one single
                     // impl block
-                    debug!("impl {:#} in {}", impl_.for_.print(&self.ctx.cache), filename);
+                    debug!(
+                        "impl {:#} in {}",
+                        impl_.for_.print(&self.ctx.cache, self.ctx.tcx),
+                        filename
+                    );
                 }
             }
             _ => {