about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-27 10:19:51 +0000
committerbors <bors@rust-lang.org>2021-01-27 10:19:51 +0000
commit613ef740f3f37702728c6324f948d0abd1e9c82b (patch)
tree5a81d39cbe7a3aa37f887a972ca71d4ae22a3ea2
parent742c972c4f92a8f213d05b82ba04797f251f125a (diff)
parentd78e1ed623d0679f20bd12ae79f41629218ff916 (diff)
downloadrust-613ef740f3f37702728c6324f948d0abd1e9c82b.tar.gz
rust-613ef740f3f37702728c6324f948d0abd1e9c82b.zip
Auto merge of #80987 - GuillaumeGomez:remove-cache-key, r=jyn514
Remove CACHE_KEY global

We realized in https://github.com/rust-lang/rust/pull/80914 that the cache handling (through a global) needed to be updated to make it much easier to handle.

r? `@jyn514`
-rw-r--r--src/librustdoc/clean/mod.rs4
-rw-r--r--src/librustdoc/clean/types.rs88
-rw-r--r--src/librustdoc/clean/utils.rs4
-rw-r--r--src/librustdoc/config.rs2
-rw-r--r--src/librustdoc/core.rs8
-rw-r--r--src/librustdoc/formats/cache.rs11
-rw-r--r--src/librustdoc/formats/mod.rs5
-rw-r--r--src/librustdoc/formats/renderer.rs33
-rw-r--r--src/librustdoc/html/format.rs507
-rw-r--r--src/librustdoc/html/render/cache.rs37
-rw-r--r--src/librustdoc/html/render/mod.rs555
-rw-r--r--src/librustdoc/json/mod.rs75
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs9
-rw-r--r--src/test/rustdoc-js-std/primitive.js75
14 files changed, 791 insertions, 622 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a116ed686d9..03454bb8b7f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2329,14 +2329,14 @@ impl Clean<Item> for (&hir::MacroDef<'_>, Option<Symbol>) {
             if matchers.len() <= 1 {
                 format!(
                     "{}macro {}{} {{\n    ...\n}}",
-                    vis.print_with_space(cx.tcx, def_id),
+                    vis.print_with_space(cx.tcx, def_id, &cx.cache),
                     name,
                     matchers.iter().map(|span| span.to_src(cx)).collect::<String>(),
                 )
             } else {
                 format!(
                     "{}macro {} {{\n{}}}",
-                    vis.print_with_space(cx.tcx, def_id),
+                    vis.print_with_space(cx.tcx, def_id, &cx.cache),
                     name,
                     matchers
                         .iter()
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index c767b9dd85b..86bce8b8707 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -37,7 +37,7 @@ use crate::clean::inline;
 use crate::clean::types::Type::{QPath, ResolvedPath};
 use crate::clean::Clean;
 use crate::core::DocContext;
-use crate::formats::cache::cache;
+use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::render::cache::ExternalLocation;
 
@@ -169,8 +169,8 @@ impl Item {
         self.attrs.collapsed_doc_value()
     }
 
-    crate fn links(&self) -> Vec<RenderedLink> {
-        self.attrs.links(&self.def_id.krate)
+    crate fn links(&self, cache: &Cache) -> Vec<RenderedLink> {
+        self.attrs.links(&self.def_id.krate, cache)
     }
 
     crate fn is_crate(&self) -> bool {
@@ -826,7 +826,7 @@ impl Attributes {
     /// Gets links as a vector
     ///
     /// Cache must be populated before call
-    crate fn links(&self, krate: &CrateNum) -> Vec<RenderedLink> {
+    crate fn links(&self, krate: &CrateNum, cache: &Cache) -> Vec<RenderedLink> {
         use crate::html::format::href;
         use crate::html::render::CURRENT_DEPTH;
 
@@ -835,7 +835,7 @@ impl Attributes {
             .filter_map(|ItemLink { link: s, link_text, did, fragment }| {
                 match *did {
                     Some(did) => {
-                        if let Some((mut href, ..)) = href(did) {
+                        if let Some((mut href, ..)) = href(did, cache) {
                             if let Some(ref fragment) = *fragment {
                                 href.push('#');
                                 href.push_str(fragment);
@@ -851,7 +851,6 @@ impl Attributes {
                     }
                     None => {
                         if let Some(ref fragment) = *fragment {
-                            let cache = cache();
                             let url = match cache.extern_locations.get(krate) {
                                 Some(&(_, _, ExternalLocation::Local)) => {
                                     let depth = CURRENT_DEPTH.with(|l| l.get());
@@ -1177,6 +1176,13 @@ impl GetDefId for FnRetTy {
             DefaultReturn => None,
         }
     }
+
+    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+        match *self {
+            Return(ref ty) => ty.def_id_full(cache),
+            DefaultReturn => None,
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -1299,13 +1305,31 @@ crate enum TypeKind {
 }
 
 crate trait GetDefId {
+    /// Use this method to get the [`DefId`] of a [`clean`] AST node.
+    /// This will return [`None`] when called on a primitive [`clean::Type`].
+    /// Use [`Self::def_id_full`] if you want to include primitives.
+    ///
+    /// [`clean`]: crate::clean
+    /// [`clean::Type`]: crate::clean::Type
+    // FIXME: get rid of this function and always use `def_id_full`
     fn def_id(&self) -> Option<DefId>;
+
+    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+    ///
+    /// See [`Self::def_id`] for more.
+    ///
+    /// [clean]: crate::clean
+    fn def_id_full(&self, cache: &Cache) -> Option<DefId>;
 }
 
 impl<T: GetDefId> GetDefId for Option<T> {
     fn def_id(&self) -> Option<DefId> {
         self.as_ref().and_then(|d| d.def_id())
     }
+
+    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+        self.as_ref().and_then(|d| d.def_id_full(cache))
+    }
 }
 
 impl Type {
@@ -1393,30 +1417,40 @@ impl Type {
     }
 }
 
-impl GetDefId for Type {
-    fn def_id(&self) -> Option<DefId> {
-        match *self {
-            ResolvedPath { did, .. } => Some(did),
-            Primitive(p) => cache().primitive_locations.get(&p).cloned(),
-            BorrowedRef { type_: box Generic(..), .. } => {
-                Primitive(PrimitiveType::Reference).def_id()
-            }
-            BorrowedRef { ref type_, .. } => type_.def_id(),
+impl Type {
+    fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
+        let t: PrimitiveType = match *self {
+            ResolvedPath { did, .. } => return Some(did),
+            Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
+            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
+            BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
             Tuple(ref tys) => {
                 if tys.is_empty() {
-                    Primitive(PrimitiveType::Unit).def_id()
+                    PrimitiveType::Unit
                 } else {
-                    Primitive(PrimitiveType::Tuple).def_id()
+                    PrimitiveType::Tuple
                 }
             }
-            BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
-            Never => Primitive(PrimitiveType::Never).def_id(),
-            Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
-            Array(..) => Primitive(PrimitiveType::Array).def_id(),
-            RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
-            QPath { ref self_type, .. } => self_type.def_id(),
-            _ => None,
-        }
+            BareFunction(..) => PrimitiveType::Fn,
+            Never => PrimitiveType::Never,
+            Slice(..) => PrimitiveType::Slice,
+            Array(..) => PrimitiveType::Array,
+            RawPointer(..) => PrimitiveType::RawPointer,
+            QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
+            // FIXME: remove this wildcard
+            _ => return None,
+        };
+        cache.and_then(|c| Primitive(t).def_id_full(c))
+    }
+}
+
+impl GetDefId for Type {
+    fn def_id(&self) -> Option<DefId> {
+        self.inner_def_id(None)
+    }
+
+    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+        self.inner_def_id(Some(cache))
     }
 }
 
@@ -1817,6 +1851,10 @@ impl GetDefId for Typedef {
     fn def_id(&self) -> Option<DefId> {
         self.type_.def_id()
     }
+
+    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+        self.type_.def_id_full(cache)
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 0f5495c8310..869d48fc25e 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -177,7 +177,7 @@ crate fn get_real_types(
         return res;
     }
     if arg.is_full_generic() {
-        let arg_s = Symbol::intern(&arg.print().to_string());
+        let arg_s = Symbol::intern(&arg.print(&cx.cache).to_string());
         if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
             WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
             _ => false,
@@ -473,7 +473,7 @@ crate fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type {
             return Generic(kw::SelfUpper);
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
-            return Generic(Symbol::intern(&format!("{:#}", path.print())));
+            return Generic(Symbol::intern(&format!("{:#}", path.print(&cx.cache))));
         }
         Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
         _ => false,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index fee1bf4c3a6..94773ac77cc 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -261,7 +261,7 @@ crate struct RenderOptions {
 }
 
 /// Temporary storage for data obtained during `RustdocVisitor::clean()`.
-/// Later on moved into `CACHE_KEY`.
+/// Later on moved into `cache`.
 #[derive(Default, Clone)]
 crate struct RenderInfo {
     crate inlined: FxHashSet<DefId>,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 4db5a0bccc8..16f11e460e6 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -32,6 +32,7 @@ use crate::clean;
 use crate::clean::{AttributesExt, MAX_DEF_ID};
 use crate::config::{Options as RustdocOptions, RenderOptions};
 use crate::config::{OutputFormat, RenderInfo};
+use crate::formats::cache::Cache;
 use crate::passes::{self, Condition::*, ConditionalPass};
 
 crate use rustc_session::config::{DebuggingOptions, Input, Options};
@@ -45,9 +46,9 @@ crate struct DocContext<'tcx> {
     ///
     /// Most of this logic is copied from rustc_lint::late.
     crate param_env: Cell<ParamEnv<'tcx>>,
-    /// Later on moved into `CACHE_KEY`
+    /// Later on moved into `cache`
     crate renderinfo: RefCell<RenderInfo>,
-    /// Later on moved through `clean::Crate` into `CACHE_KEY`
+    /// Later on moved through `clean::Crate` into `cache`
     crate external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
     /// Used while populating `external_traits` to ensure we don't process the same trait twice at
     /// the same time.
@@ -75,6 +76,8 @@ crate struct DocContext<'tcx> {
     /// See `collect_intra_doc_links::traits_implemented_by` for more details.
     /// `map<module, set<trait>>`
     crate module_trait_cache: RefCell<FxHashMap<DefId, FxHashSet<DefId>>>,
+    /// Fake empty cache used when cache is required as parameter.
+    crate cache: Cache,
 }
 
 impl<'tcx> DocContext<'tcx> {
@@ -524,6 +527,7 @@ crate fn run_global_ctxt(
             .collect(),
         render_options,
         module_trait_cache: RefCell::new(FxHashMap::default()),
+        cache: Cache::default(),
     };
     debug!("crate: {:?}", tcx.hir().krate());
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index c1f8b12cac4..c506f5a37b1 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,8 +1,6 @@
-use std::cell::RefCell;
 use std::collections::BTreeMap;
 use std::mem;
 use std::path::{Path, PathBuf};
-use std::sync::Arc;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
@@ -19,8 +17,6 @@ use crate::html::markdown::short_markdown_summary;
 use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation};
 use crate::html::render::IndexItem;
 
-thread_local!(crate static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
-
 /// This cache is used to store information about the [`clean::Crate`] being
 /// rendered in order to provide more useful documentation. This contains
 /// information like all implementors of a trait, all traits a type implements,
@@ -197,6 +193,7 @@ impl Cache {
         }
 
         cache.stack.push(krate.name.to_string());
+
         krate = cache.fold_crate(krate);
 
         for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
@@ -319,7 +316,7 @@ impl DocFolder for Cache {
                                 .map_or_else(String::new, |x| short_markdown_summary(&x.as_str())),
                             parent,
                             parent_idx: None,
-                            search_type: get_index_search_type(&item),
+                            search_type: get_index_search_type(&item, None),
                         });
 
                         for alias in item.attrs.get_doc_aliases() {
@@ -477,7 +474,3 @@ impl DocFolder for Cache {
         ret
     }
 }
-
-crate fn cache() -> Arc<Cache> {
-    CACHE_KEY.with(|c| c.borrow().clone())
-}
diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs
index 58b9f5fbf0f..1ce6572bbed 100644
--- a/src/librustdoc/formats/mod.rs
+++ b/src/librustdoc/formats/mod.rs
@@ -8,6 +8,7 @@ use rustc_span::def_id::DefId;
 
 use crate::clean;
 use crate::clean::types::GetDefId;
+use crate::formats::cache::Cache;
 
 /// Specifies whether rendering directly implemented trait items or ones from a certain Deref
 /// impl.
@@ -41,4 +42,8 @@ impl Impl {
     crate fn trait_did(&self) -> Option<DefId> {
         self.inner_impl().trait_.def_id()
     }
+
+    crate fn trait_did_full(&self, cache: &Cache) -> Option<DefId> {
+        self.inner_impl().trait_.def_id_full(cache)
+    }
 }
diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs
index 6941fa064ec..6ecc4695dc8 100644
--- a/src/librustdoc/formats/renderer.rs
+++ b/src/librustdoc/formats/renderer.rs
@@ -1,12 +1,10 @@
-use std::sync::Arc;
-
 use rustc_middle::ty::TyCtxt;
 use rustc_span::edition::Edition;
 
 use crate::clean;
 use crate::config::{RenderInfo, RenderOptions};
 use crate::error::Error;
-use crate::formats::cache::{Cache, CACHE_KEY};
+use crate::formats::cache::Cache;
 
 /// Allows for different backends to rustdoc to be used with the `run_format()` function. Each
 /// backend renderer has hooks for initialization, documenting an item, entering and exiting a
@@ -22,20 +20,15 @@ crate trait FormatRenderer<'tcx>: Clone {
         options: RenderOptions,
         render_info: RenderInfo,
         edition: Edition,
-        cache: &mut Cache,
+        cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error>;
 
     /// Renders a single non-module item. This means no recursive sub-item rendering is required.
-    fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error>;
+    fn item(&mut self, item: clean::Item) -> Result<(), Error>;
 
     /// Renders a module (should not handle recursing into children).
-    fn mod_item_in(
-        &mut self,
-        item: &clean::Item,
-        item_name: &str,
-        cache: &Cache,
-    ) -> Result<(), Error>;
+    fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error>;
 
     /// Runs after recursively rendering all sub-items of a module.
     fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>;
@@ -46,9 +39,10 @@ crate trait FormatRenderer<'tcx>: Clone {
     fn after_krate(
         &mut self,
         krate: &clean::Crate,
-        cache: &Cache,
         diag: &rustc_errors::Handler,
     ) -> Result<(), Error>;
+
+    fn cache(&self) -> &Cache;
 }
 
 /// Main method for rendering a crate.
@@ -60,7 +54,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
     edition: Edition,
     tcx: TyCtxt<'tcx>,
 ) -> Result<(), Error> {
-    let (krate, mut cache) = tcx.sess.time("create_format_cache", || {
+    let (krate, cache) = tcx.sess.time("create_format_cache", || {
         Cache::from_krate(
             render_info.clone(),
             options.document_private,
@@ -73,12 +67,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
 
     let (mut format_renderer, mut krate) = prof
         .extra_verbose_generic_activity("create_renderer", T::descr())
-        .run(|| T::init(krate, options, render_info, edition, &mut cache, tcx))?;
-
-    let cache = Arc::new(cache);
-    // Freeze the cache now that the index has been built. Put an Arc into TLS for future
-    // parallelization opportunities
-    CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
+        .run(|| T::init(krate, options, render_info, edition, cache, tcx))?;
 
     let mut item = match krate.module.take() {
         Some(i) => i,
@@ -101,7 +90,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
             }
             let _timer = prof.generic_activity_with_arg("render_mod_item", name.as_str());
 
-            cx.mod_item_in(&item, &name, &cache)?;
+            cx.mod_item_in(&item, &name)?;
             let module = match *item.kind {
                 clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
                 _ => unreachable!(),
@@ -114,9 +103,9 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
             cx.mod_item_out(&name)?;
         } else if item.name.is_some() {
             prof.generic_activity_with_arg("render_item", &*item.name.unwrap_or(unknown).as_str())
-                .run(|| cx.item(item, &cache))?;
+                .run(|| cx.item(item))?;
         }
     }
     prof.extra_verbose_generic_activity("renderer_after_krate", T::descr())
-        .run(|| format_renderer.after_krate(&krate, &cache, diag))
+        .run(|| format_renderer.after_krate(&krate, diag))
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 5c2adca3126..01915c33a07 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -16,7 +16,7 @@ use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_target::spec::abi::Abi;
 
 use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType};
-use crate::formats::cache::cache;
+use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::render::cache::ExternalLocation;
@@ -152,24 +152,27 @@ fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Displ
     })
 }
 
-crate fn print_generic_bounds(bounds: &[clean::GenericBound]) -> impl fmt::Display + '_ {
+crate fn print_generic_bounds<'a>(
+    bounds: &'a [clean::GenericBound],
+    cache: &'a Cache,
+) -> impl fmt::Display + 'a {
     display_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
 
         for (i, bound) in
-            bounds.iter().filter(|b| bounds_dup.insert(b.print().to_string())).enumerate()
+            bounds.iter().filter(|b| bounds_dup.insert(b.print(cache).to_string())).enumerate()
         {
             if i > 0 {
                 f.write_str(" + ")?;
             }
-            fmt::Display::fmt(&bound.print(), f)?;
+            fmt::Display::fmt(&bound.print(cache), f)?;
         }
         Ok(())
     })
 }
 
 impl clean::GenericParamDef {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| match self.kind {
             clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
             clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
@@ -177,17 +180,17 @@ impl clean::GenericParamDef {
 
                 if !bounds.is_empty() {
                     if f.alternate() {
-                        write!(f, ": {:#}", print_generic_bounds(bounds))?;
+                        write!(f, ": {:#}", print_generic_bounds(bounds, cache))?;
                     } else {
-                        write!(f, ":&nbsp;{}", print_generic_bounds(bounds))?;
+                        write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache))?;
                     }
                 }
 
                 if let Some(ref ty) = default {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty.print())?;
+                        write!(f, " = {:#}", ty.print(cache))?;
                     } else {
-                        write!(f, "&nbsp;=&nbsp;{}", ty.print())?;
+                        write!(f, "&nbsp;=&nbsp;{}", ty.print(cache))?;
                     }
                 }
 
@@ -195,9 +198,9 @@ impl clean::GenericParamDef {
             }
             clean::GenericParamDefKind::Const { ref ty, .. } => {
                 if f.alternate() {
-                    write!(f, "const {}: {:#}", self.name, ty.print())
+                    write!(f, "const {}: {:#}", self.name, ty.print(cache))
                 } else {
-                    write!(f, "const {}:&nbsp;{}", self.name, ty.print())
+                    write!(f, "const {}:&nbsp;{}", self.name, ty.print(cache))
                 }
             }
         })
@@ -205,7 +208,7 @@ impl clean::GenericParamDef {
 }
 
 impl clean::Generics {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| {
             let real_params =
                 self.params.iter().filter(|p| !p.is_synthetic_type_param()).collect::<Vec<_>>();
@@ -213,98 +216,108 @@ impl clean::Generics {
                 return Ok(());
             }
             if f.alternate() {
-                write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print())))
+                write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cache))))
             } else {
-                write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print())))
+                write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print(cache))))
             }
         })
     }
 }
 
-impl<'a> fmt::Display for WhereClause<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let &WhereClause { gens, indent, end_newline } = self;
-        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");
+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(());
             }
-        }
-        for (i, pred) in gens.where_predicates.iter().enumerate() {
+            let mut clause = String::new();
             if f.alternate() {
-                clause.push(' ');
+                clause.push_str(" where");
             } else {
-                clause.push_str("<br>");
+                if end_newline {
+                    clause.push_str(" <span class=\"where fmt-newline\">where");
+                } else {
+                    clause.push_str(" <span class=\"where\">where");
+                }
             }
+            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(),
-                            print_generic_bounds(bounds)
-                        ));
-                    } else {
+                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 } => {
                         clause.push_str(&format!(
                             "{}: {}",
-                            ty.print(),
-                            print_generic_bounds(bounds)
+                            lifetime.print(),
+                            bounds
+                                .iter()
+                                .map(|b| b.print(cache).to_string())
+                                .collect::<Vec<_>>()
+                                .join(" + ")
                         ));
                     }
-                }
-                clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
-                    clause.push_str(&format!(
-                        "{}: {}",
-                        lifetime.print(),
-                        bounds
-                            .iter()
-                            .map(|b| b.print().to_string())
-                            .collect::<Vec<_>>()
-                            .join(" + ")
-                    ));
-                }
-                clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                    if f.alternate() {
-                        clause.push_str(&format!("{:#} == {:#}", lhs.print(), rhs.print()));
-                    } else {
-                        clause.push_str(&format!("{} == {}", lhs.print(), rhs.print()));
+                    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)
+                            ));
+                        }
                     }
                 }
-            }
 
-            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)
+        })
     }
 }
 
@@ -327,34 +340,34 @@ impl clean::Constant {
 }
 
 impl clean::PolyTrait {
-    fn print(&self) -> impl fmt::Display + '_ {
+    fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         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()))
+                        comma_sep(self.generic_params.iter().map(|g| g.print(cache)))
                     )?;
                 } else {
                     write!(
                         f,
                         "for&lt;{}&gt; ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print()))
+                        comma_sep(self.generic_params.iter().map(|g| g.print(cache)))
                     )?;
                 }
             }
             if f.alternate() {
-                write!(f, "{:#}", self.trait_.print())
+                write!(f, "{:#}", self.trait_.print(cache))
             } else {
-                write!(f, "{}", self.trait_.print())
+                write!(f, "{}", self.trait_.print(cache))
             }
         })
     }
 }
 
 impl clean::GenericBound {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
             clean::GenericBound::TraitBound(ty, modifier) => {
@@ -364,9 +377,9 @@ impl clean::GenericBound {
                     hir::TraitBoundModifier::MaybeConst => "?const",
                 };
                 if f.alternate() {
-                    write!(f, "{}{:#}", modifier_str, ty.print())
+                    write!(f, "{}{:#}", modifier_str, ty.print(cache))
                 } else {
-                    write!(f, "{}{}", modifier_str, ty.print())
+                    write!(f, "{}{}", modifier_str, ty.print(cache))
                 }
             }
         })
@@ -374,7 +387,7 @@ impl clean::GenericBound {
 }
 
 impl clean::GenericArgs {
-    fn print(&self) -> impl fmt::Display + '_ {
+    fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| {
             match self {
                 clean::GenericArgs::AngleBracketed { args, bindings } => {
@@ -391,9 +404,9 @@ impl clean::GenericArgs {
                             }
                             comma = true;
                             if f.alternate() {
-                                write!(f, "{:#}", arg.print())?;
+                                write!(f, "{:#}", arg.print(cache))?;
                             } else {
-                                write!(f, "{}", arg.print())?;
+                                write!(f, "{}", arg.print(cache))?;
                             }
                         }
                         for binding in bindings {
@@ -402,9 +415,9 @@ impl clean::GenericArgs {
                             }
                             comma = true;
                             if f.alternate() {
-                                write!(f, "{:#}", binding.print())?;
+                                write!(f, "{:#}", binding.print(cache))?;
                             } else {
-                                write!(f, "{}", binding.print())?;
+                                write!(f, "{}", binding.print(cache))?;
                             }
                         }
                         if f.alternate() {
@@ -423,17 +436,17 @@ impl clean::GenericArgs {
                         }
                         comma = true;
                         if f.alternate() {
-                            write!(f, "{:#}", ty.print())?;
+                            write!(f, "{:#}", ty.print(cache))?;
                         } else {
-                            write!(f, "{}", ty.print())?;
+                            write!(f, "{}", ty.print(cache))?;
                         }
                     }
                     f.write_str(")")?;
                     if let Some(ref ty) = *output {
                         if f.alternate() {
-                            write!(f, " -> {:#}", ty.print())?;
+                            write!(f, " -> {:#}", ty.print(cache))?;
                         } else {
-                            write!(f, " -&gt; {}", ty.print())?;
+                            write!(f, " -&gt; {}", ty.print(cache))?;
                         }
                     }
                 }
@@ -444,19 +457,19 @@ impl clean::GenericArgs {
 }
 
 impl clean::PathSegment {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| {
             if f.alternate() {
-                write!(f, "{}{:#}", self.name, self.args.print())
+                write!(f, "{}{:#}", self.name, self.args.print(cache))
             } else {
-                write!(f, "{}{}", self.name, self.args.print())
+                write!(f, "{}{}", self.name, self.args.print(cache))
             }
         })
     }
 }
 
 impl clean::Path {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| {
             if self.global {
                 f.write_str("::")?
@@ -467,9 +480,9 @@ impl clean::Path {
                     f.write_str("::")?
                 }
                 if f.alternate() {
-                    write!(f, "{:#}", seg.print())?;
+                    write!(f, "{:#}", seg.print(cache))?;
                 } else {
-                    write!(f, "{}", seg.print())?;
+                    write!(f, "{}", seg.print(cache))?;
                 }
             }
             Ok(())
@@ -477,8 +490,7 @@ impl clean::Path {
     }
 }
 
-crate fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
-    let cache = cache();
+crate fn href(did: DefId, cache: &Cache) -> Option<(String, ItemType, Vec<String>)> {
     if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
         return None;
     }
@@ -526,6 +538,7 @@ fn resolved_path(
     path: &clean::Path,
     print_all: bool,
     use_absolute: bool,
+    cache: &Cache,
 ) -> fmt::Result {
     let last = path.segments.last().unwrap();
 
@@ -535,18 +548,22 @@ fn resolved_path(
         }
     }
     if w.alternate() {
-        write!(w, "{}{:#}", &last.name, last.args.print())?;
+        write!(w, "{}{:#}", &last.name, last.args.print(cache))?;
     } else {
         let path = if use_absolute {
-            if let Some((_, _, fqp)) = href(did) {
-                format!("{}::{}", fqp[..fqp.len() - 1].join("::"), anchor(did, fqp.last().unwrap()))
+            if let Some((_, _, fqp)) = href(did, cache) {
+                format!(
+                    "{}::{}",
+                    fqp[..fqp.len() - 1].join("::"),
+                    anchor(did, fqp.last().unwrap(), cache)
+                )
             } else {
                 last.name.to_string()
             }
         } else {
-            anchor(did, &*last.name.as_str()).to_string()
+            anchor(did, &*last.name.as_str(), cache).to_string()
         };
-        write!(w, "{}{}", path, last.args.print())?;
+        write!(w, "{}{}", path, last.args.print(cache))?;
     }
     Ok(())
 }
@@ -555,8 +572,8 @@ fn primitive_link(
     f: &mut fmt::Formatter<'_>,
     prim: clean::PrimitiveType,
     name: &str,
+    m: &Cache,
 ) -> fmt::Result {
-    let m = cache();
     let mut needs_termination = false;
     if !f.alternate() {
         match m.primitive_locations.get(&prim) {
@@ -602,12 +619,15 @@ fn primitive_link(
 }
 
 /// Helper to render type parameters
-fn tybounds(param_names: &Option<Vec<clean::GenericBound>>) -> impl fmt::Display + '_ {
+fn tybounds<'a>(
+    param_names: &'a Option<Vec<clean::GenericBound>>,
+    cache: &'a Cache,
+) -> impl fmt::Display + 'a {
     display_fn(move |f| match *param_names {
         Some(ref params) => {
             for param in params {
                 write!(f, " + ")?;
-                fmt::Display::fmt(&param.print(), f)?;
+                fmt::Display::fmt(&param.print(cache), f)?;
             }
             Ok(())
         }
@@ -615,9 +635,9 @@ fn tybounds(param_names: &Option<Vec<clean::GenericBound>>) -> impl fmt::Display
     })
 }
 
-crate fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ {
+crate fn anchor<'a>(did: DefId, text: &'a str, cache: &'a Cache) -> impl fmt::Display + 'a {
     display_fn(move |f| {
-        if let Some((url, short_ty, fqp)) = href(did) {
+        if let Some((url, short_ty, fqp)) = href(did, cache) {
             write!(
                 f,
                 r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
@@ -633,7 +653,12 @@ crate fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ {
     })
 }
 
-fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result {
+fn fmt_type(
+    t: &clean::Type,
+    f: &mut fmt::Formatter<'_>,
+    use_absolute: bool,
+    cache: &Cache,
+) -> fmt::Result {
     match *t {
         clean::Generic(name) => write!(f, "{}", name),
         clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
@@ -641,11 +666,11 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                 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)?;
-            fmt::Display::fmt(&tybounds(param_names), f)
+            resolved_path(f, did, path, is_generic, use_absolute, cache)?;
+            fmt::Display::fmt(&tybounds(param_names, cache), f)
         }
         clean::Infer => write!(f, "_"),
-        clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
+        clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cache),
         clean::BareFunction(ref decl) => {
             if f.alternate() {
                 write!(
@@ -653,8 +678,8 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                     "{}{:#}fn{:#}{:#}",
                     decl.unsafety.print_with_space(),
                     print_abi_with_space(decl.abi),
-                    decl.print_generic_params(),
-                    decl.decl.print()
+                    decl.print_generic_params(cache),
+                    decl.decl.print(cache)
                 )
             } else {
                 write!(
@@ -663,46 +688,46 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                     decl.unsafety.print_with_space(),
                     print_abi_with_space(decl.abi)
                 )?;
-                primitive_link(f, PrimitiveType::Fn, "fn")?;
-                write!(f, "{}{}", decl.print_generic_params(), decl.decl.print())
+                primitive_link(f, PrimitiveType::Fn, "fn", cache)?;
+                write!(f, "{}{}", decl.print_generic_params(cache), decl.decl.print(cache))
             }
         }
         clean::Tuple(ref typs) => {
             match &typs[..] {
-                &[] => primitive_link(f, PrimitiveType::Unit, "()"),
+                &[] => primitive_link(f, PrimitiveType::Unit, "()", cache),
                 &[ref one] => {
-                    primitive_link(f, PrimitiveType::Tuple, "(")?;
+                    primitive_link(f, PrimitiveType::Tuple, "(", cache)?;
                     // Carry `f.alternate()` into this display w/o branching manually.
-                    fmt::Display::fmt(&one.print(), f)?;
-                    primitive_link(f, PrimitiveType::Tuple, ",)")
+                    fmt::Display::fmt(&one.print(cache), f)?;
+                    primitive_link(f, PrimitiveType::Tuple, ",)", cache)
                 }
                 many => {
-                    primitive_link(f, PrimitiveType::Tuple, "(")?;
+                    primitive_link(f, PrimitiveType::Tuple, "(", cache)?;
                     for (i, item) in many.iter().enumerate() {
                         if i != 0 {
                             write!(f, ", ")?;
                         }
-                        fmt::Display::fmt(&item.print(), f)?;
+                        fmt::Display::fmt(&item.print(cache), f)?;
                     }
-                    primitive_link(f, PrimitiveType::Tuple, ")")
+                    primitive_link(f, PrimitiveType::Tuple, ")", cache)
                 }
             }
         }
         clean::Slice(ref t) => {
-            primitive_link(f, PrimitiveType::Slice, "[")?;
-            fmt::Display::fmt(&t.print(), f)?;
-            primitive_link(f, PrimitiveType::Slice, "]")
+            primitive_link(f, PrimitiveType::Slice, "[", cache)?;
+            fmt::Display::fmt(&t.print(cache), f)?;
+            primitive_link(f, PrimitiveType::Slice, "]", cache)
         }
         clean::Array(ref t, ref n) => {
-            primitive_link(f, PrimitiveType::Array, "[")?;
-            fmt::Display::fmt(&t.print(), f)?;
+            primitive_link(f, PrimitiveType::Array, "[", cache)?;
+            fmt::Display::fmt(&t.print(cache), f)?;
             if f.alternate() {
-                primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
+                primitive_link(f, PrimitiveType::Array, &format!("; {}]", n), cache)
             } else {
-                primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)))
+                primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)), cache)
             }
         }
-        clean::Never => primitive_link(f, PrimitiveType::Never, "!"),
+        clean::Never => primitive_link(f, PrimitiveType::Never, "!", cache),
         clean::RawPointer(m, ref t) => {
             let m = match m {
                 hir::Mutability::Mut => "mut",
@@ -714,19 +739,26 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                         primitive_link(
                             f,
                             clean::PrimitiveType::RawPointer,
-                            &format!("*{} {:#}", m, t.print()),
+                            &format!("*{} {:#}", m, t.print(cache)),
+                            cache,
                         )
                     } else {
                         primitive_link(
                             f,
                             clean::PrimitiveType::RawPointer,
-                            &format!("*{} {}", m, t.print()),
+                            &format!("*{} {}", m, t.print(cache)),
+                            cache,
                         )
                     }
                 }
                 _ => {
-                    primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m))?;
-                    fmt::Display::fmt(&t.print(), f)
+                    primitive_link(
+                        f,
+                        clean::PrimitiveType::RawPointer,
+                        &format!("*{} ", m),
+                        cache,
+                    )?;
+                    fmt::Display::fmt(&t.print(cache), f)
                 }
             }
         }
@@ -746,13 +778,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                                 primitive_link(
                                     f,
                                     PrimitiveType::Slice,
-                                    &format!("{}{}{}[{:#}]", amp, lt, m, bt.print()),
+                                    &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cache)),
+                                    cache,
                                 )
                             } else {
                                 primitive_link(
                                     f,
                                     PrimitiveType::Slice,
-                                    &format!("{}{}{}[{}]", amp, lt, m, bt.print()),
+                                    &format!("{}{}{}[{}]", amp, lt, m, bt.print(cache)),
+                                    cache,
                                 )
                             }
                         }
@@ -761,36 +795,42 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                                 f,
                                 PrimitiveType::Slice,
                                 &format!("{}{}{}[", amp, lt, m),
+                                cache,
                             )?;
                             if f.alternate() {
-                                write!(f, "{:#}", bt.print())?;
+                                write!(f, "{:#}", bt.print(cache))?;
                             } else {
-                                write!(f, "{}", bt.print())?;
+                                write!(f, "{}", bt.print(cache))?;
                             }
-                            primitive_link(f, PrimitiveType::Slice, "]")
+                            primitive_link(f, PrimitiveType::Slice, "]", cache)
                         }
                     }
                 }
                 clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => {
                     write!(f, "{}{}{}(", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute)?;
+                    fmt_type(&ty, f, use_absolute, cache)?;
                     write!(f, ")")
                 }
                 clean::Generic(..) => {
-                    primitive_link(f, PrimitiveType::Reference, &format!("{}{}{}", amp, lt, m))?;
-                    fmt_type(&ty, f, use_absolute)
+                    primitive_link(
+                        f,
+                        PrimitiveType::Reference,
+                        &format!("{}{}{}", amp, lt, m),
+                        cache,
+                    )?;
+                    fmt_type(&ty, f, use_absolute, cache)
                 }
                 _ => {
                     write!(f, "{}{}{}", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute)
+                    fmt_type(&ty, f, use_absolute, cache)
                 }
             }
         }
         clean::ImplTrait(ref bounds) => {
             if f.alternate() {
-                write!(f, "impl {:#}", print_generic_bounds(bounds))
+                write!(f, "impl {:#}", print_generic_bounds(bounds, cache))
             } else {
-                write!(f, "impl {}", print_generic_bounds(bounds))
+                write!(f, "impl {}", print_generic_bounds(bounds, cache))
             }
         }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
@@ -802,15 +842,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
             };
             if f.alternate() {
                 if should_show_cast {
-                    write!(f, "<{:#} as {:#}>::", self_type.print(), trait_.print())?
+                    write!(f, "<{:#} as {:#}>::", self_type.print(cache), trait_.print(cache))?
                 } else {
-                    write!(f, "{:#}::", self_type.print())?
+                    write!(f, "{:#}::", self_type.print(cache))?
                 }
             } else {
                 if should_show_cast {
-                    write!(f, "&lt;{} as {}&gt;::", self_type.print(), trait_.print())?
+                    write!(f, "&lt;{} as {}&gt;::", self_type.print(cache), trait_.print(cache))?
                 } else {
-                    write!(f, "{}::", self_type.print())?
+                    write!(f, "{}::", self_type.print(cache))?
                 }
             };
             match *trait_ {
@@ -825,7 +865,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                 //        everything comes in as a fully resolved QPath (hard to
                 //        look at).
                 box clean::ResolvedPath { did, ref param_names, .. } => {
-                    match href(did) {
+                    match href(did, cache) {
                         Some((ref url, _, ref path)) if !f.alternate() => {
                             write!(
                                 f,
@@ -851,22 +891,27 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
 }
 
 impl clean::Type {
-    crate fn print(&self) -> impl fmt::Display + '_ {
-        display_fn(move |f| fmt_type(self, f, false))
+    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))
     }
 }
 
 impl clean::Impl {
-    crate fn print(&self) -> impl fmt::Display + '_ {
-        self.print_inner(true, false)
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+        self.print_inner(true, false, cache)
     }
 
-    fn print_inner(&self, link_trait: bool, use_absolute: bool) -> impl fmt::Display + '_ {
+    fn print_inner<'a>(
+        &'a self,
+        link_trait: bool,
+        use_absolute: bool,
+        cache: &'a Cache,
+    ) -> impl fmt::Display + 'a {
         display_fn(move |f| {
             if f.alternate() {
-                write!(f, "impl{:#} ", self.generics.print())?;
+                write!(f, "impl{:#} ", self.generics.print(cache))?;
             } else {
-                write!(f, "impl{} ", self.generics.print())?;
+                write!(f, "impl{} ", self.generics.print(cache))?;
             }
 
             if let Some(ref ty) = self.trait_ {
@@ -875,7 +920,7 @@ impl clean::Impl {
                 }
 
                 if link_trait {
-                    fmt::Display::fmt(&ty.print(), f)?;
+                    fmt::Display::fmt(&ty.print(cache), f)?;
                 } else {
                     match ty {
                         clean::ResolvedPath {
@@ -883,7 +928,7 @@ impl clean::Impl {
                         } => {
                             let last = path.segments.last().unwrap();
                             fmt::Display::fmt(&last.name, f)?;
-                            fmt::Display::fmt(&last.args.print(), f)?;
+                            fmt::Display::fmt(&last.args.print(cache), f)?;
                         }
                         _ => unreachable!(),
                     }
@@ -892,36 +937,39 @@ impl clean::Impl {
             }
 
             if let Some(ref ty) = self.blanket_impl {
-                fmt_type(ty, f, use_absolute)?;
+                fmt_type(ty, f, use_absolute, cache)?;
             } else {
-                fmt_type(&self.for_, f, use_absolute)?;
+                fmt_type(&self.for_, f, use_absolute, cache)?;
             }
 
-            fmt::Display::fmt(
-                &WhereClause { gens: &self.generics, indent: 0, end_newline: true },
-                f,
-            )?;
+            let where_clause = WhereClause { gens: &self.generics, indent: 0, end_newline: true };
+            fmt::Display::fmt(&where_clause.print(cache), f)?;
             Ok(())
         })
     }
 }
 
 // The difference from above is that trait is not hyperlinked.
-crate fn fmt_impl_for_trait_page(i: &clean::Impl, f: &mut Buffer, use_absolute: bool) {
-    f.from_display(i.print_inner(false, use_absolute))
+crate fn fmt_impl_for_trait_page(
+    i: &clean::Impl,
+    f: &mut Buffer,
+    use_absolute: bool,
+    cache: &Cache,
+) {
+    f.from_display(i.print_inner(false, use_absolute, cache))
 }
 
 impl clean::Arguments {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         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())?;
+                    write!(f, "{:#}", input.type_.print(cache))?;
                 } else {
-                    write!(f, "{}", input.type_.print())?;
+                    write!(f, "{}", input.type_.print(cache))?;
                 }
                 if i + 1 < self.values.len() {
                     write!(f, ", ")?;
@@ -933,41 +981,41 @@ impl clean::Arguments {
 }
 
 impl clean::FnRetTy {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         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()),
-            clean::Return(ty) => write!(f, " -&gt; {}", ty.print()),
+            clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print(cache)),
+            clean::Return(ty) => write!(f, " -&gt; {}", ty.print(cache)),
             clean::DefaultReturn => Ok(()),
         })
     }
 }
 
 impl clean::BareFunctionDecl {
-    fn print_generic_params(&self) -> impl fmt::Display + '_ {
-        comma_sep(self.generic_params.iter().map(|g| g.print()))
+    fn print_generic_params<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
+        comma_sep(self.generic_params.iter().map(move |g| g.print(cache)))
     }
 }
 
 impl clean::FnDecl {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
         display_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
                 write!(
                     f,
                     "({args:#}{ellipsis}){arrow:#}",
-                    args = self.inputs.print(),
+                    args = self.inputs.print(cache),
                     ellipsis = ellipsis,
-                    arrow = self.output.print()
+                    arrow = self.output.print(cache)
                 )
             } else {
                 write!(
                     f,
                     "({args}{ellipsis}){arrow}",
-                    args = self.inputs.print(),
+                    args = self.inputs.print(cache),
                     ellipsis = ellipsis,
-                    arrow = self.output.print()
+                    arrow = self.output.print(cache)
                 )
             }
         })
@@ -975,7 +1023,7 @@ impl clean::FnDecl {
 }
 
 impl Function<'_> {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    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;" };
@@ -1011,11 +1059,11 @@ impl Function<'_> {
                         }
                         clean::SelfExplicit(ref typ) => {
                             if f.alternate() {
-                                args.push_str(&format!("self: {:#}", typ.print()));
+                                args.push_str(&format!("self: {:#}", typ.print(cache)));
                             } else {
-                                args.push_str(&format!("self: {}", typ.print()));
+                                args.push_str(&format!("self: {}", typ.print(cache)));
                             }
-                            args_plain.push_str(&format!("self: {:#}", typ.print()));
+                            args_plain.push_str(&format!("self: {:#}", typ.print(cache)));
                         }
                     }
                 } else {
@@ -1029,11 +1077,11 @@ impl Function<'_> {
                     }
 
                     if f.alternate() {
-                        args.push_str(&format!("{:#}", input.type_.print()));
+                        args.push_str(&format!("{:#}", input.type_.print(cache)));
                     } else {
-                        args.push_str(&input.type_.print().to_string());
+                        args.push_str(&input.type_.print(cache).to_string());
                     }
-                    args_plain.push_str(&format!("{:#}", input.type_.print()));
+                    args_plain.push_str(&format!("{:#}", input.type_.print(cache)));
                 }
                 if i + 1 < decl.inputs.values.len() {
                     args.push(',');
@@ -1054,11 +1102,11 @@ impl Function<'_> {
                 Cow::Borrowed(&decl.output)
             };
 
-            let arrow_plain = format!("{:#}", &output.print());
+            let arrow_plain = format!("{:#}", &output.print(cache));
             let arrow = if f.alternate() {
-                format!("{:#}", &output.print())
+                format!("{:#}", &output.print(cache))
             } else {
-                output.print().to_string()
+                output.print(cache).to_string()
             };
 
             let declaration_len = header_len + args_plain.len() + arrow_plain.len();
@@ -1089,13 +1137,13 @@ impl clean::Visibility {
         self,
         tcx: TyCtxt<'tcx>,
         item_did: DefId,
+        cache: &Cache,
     ) -> impl fmt::Display + 'tcx {
         use rustc_span::symbol::kw;
 
-        display_fn(move |f| match self {
-            clean::Public => f.write_str("pub "),
-            clean::Inherited => Ok(()),
-
+        let to_print = match self {
+            clean::Public => "pub ".to_owned(),
+            clean::Inherited => String::new(),
             clean::Visibility::Restricted(vis_did) => {
                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
                 //                 However, rustdoc currently never displays a module's
@@ -1103,38 +1151,41 @@ impl clean::Visibility {
                 let parent_module = find_nearest_parent_module(tcx, item_did);
 
                 if vis_did.index == CRATE_DEF_INDEX {
-                    write!(f, "pub(crate) ")
+                    "pub(crate) ".to_owned()
                 } else if parent_module == Some(vis_did) {
                     // `pub(in foo)` where `foo` is the parent module
                     // is the same as no visibility modifier
-                    Ok(())
+                    String::new()
                 } else if parent_module
                     .map(|parent| find_nearest_parent_module(tcx, parent))
                     .flatten()
                     == Some(vis_did)
                 {
-                    write!(f, "pub(super) ")
+                    "pub(super) ".to_owned()
                 } else {
-                    f.write_str("pub(")?;
                     let path = tcx.def_path(vis_did);
                     debug!("path={:?}", path);
                     let first_name =
                         path.data[0].data.get_opt_name().expect("modules are always named");
+                    // modified from `resolved_path()` to work with `DefPathData`
+                    let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
+                    let anchor = anchor(vis_did, &last_name.as_str(), cache).to_string();
+
+                    let mut s = "pub(".to_owned();
                     if path.data.len() != 1
                         || (first_name != kw::SelfLower && first_name != kw::Super)
                     {
-                        f.write_str("in ")?;
+                        s.push_str("in ");
                     }
-                    // modified from `resolved_path()` to work with `DefPathData`
-                    let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
                     for seg in &path.data[..path.data.len() - 1] {
-                        write!(f, "{}::", seg.data.get_opt_name().unwrap())?;
+                        s.push_str(&format!("{}::", seg.data.get_opt_name().unwrap()));
                     }
-                    let path = anchor(vis_did, &last_name.as_str()).to_string();
-                    write!(f, "{}) ", path)
+                    s.push_str(&format!("{}) ", anchor));
+                    s
                 }
             }
-        })
+        };
+        display_fn(move |f| f.write_str(&to_print))
     }
 }
 
@@ -1179,20 +1230,20 @@ impl PrintWithSpace for hir::Mutability {
 }
 
 impl clean::Import {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
         display_fn(move |f| match self.kind {
             clean::ImportKind::Simple(name) => {
                 if name == self.source.path.last() {
-                    write!(f, "use {};", self.source.print())
+                    write!(f, "use {};", self.source.print(cache))
                 } else {
-                    write!(f, "use {} as {};", self.source.print(), name)
+                    write!(f, "use {} as {};", self.source.print(cache), name)
                 }
             }
             clean::ImportKind::Glob => {
                 if self.source.path.segments.is_empty() {
                     write!(f, "use *;")
                 } else {
-                    write!(f, "use {}::*;", self.source.print())
+                    write!(f, "use {}::*;", self.source.print(cache))
                 }
             }
         })
@@ -1200,16 +1251,16 @@ impl clean::Import {
 }
 
 impl clean::ImportSource {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
         display_fn(move |f| match self.did {
-            Some(did) => resolved_path(f, did, &self.path, true, false),
+            Some(did) => resolved_path(f, did, &self.path, true, false, cache),
             _ => {
                 for seg in &self.path.segments[..self.path.segments.len() - 1] {
                     write!(f, "{}::", seg.name)?;
                 }
                 let name = self.path.last_name();
                 if let hir::def::Res::PrimTy(p) = self.path.res {
-                    primitive_link(f, PrimitiveType::from(p), &*name)?;
+                    primitive_link(f, PrimitiveType::from(p), &*name, cache)?;
                 } else {
                     write!(f, "{}", name)?;
                 }
@@ -1220,23 +1271,23 @@ impl clean::ImportSource {
 }
 
 impl clean::TypeBinding {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
         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())?;
+                        write!(f, " = {:#}", ty.print(cache))?;
                     } else {
-                        write!(f, " = {}", ty.print())?;
+                        write!(f, " = {}", ty.print(cache))?;
                     }
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
                     if !bounds.is_empty() {
                         if f.alternate() {
-                            write!(f, ": {:#}", print_generic_bounds(bounds))?;
+                            write!(f, ": {:#}", print_generic_bounds(bounds, cache))?;
                         } else {
-                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds))?;
+                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache))?;
                         }
                     }
                 }
@@ -1261,10 +1312,10 @@ crate fn print_default_space<'a>(v: bool) -> &'a str {
 }
 
 impl clean::GenericArg {
-    crate fn print(&self) -> impl fmt::Display + '_ {
+    crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
         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(), f),
+            clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cache), f),
             clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f),
         })
     }
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 497cbbb4250..5c02be14181 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -67,31 +67,31 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
     let mut crate_paths = vec![];
 
-    let Cache { ref mut search_index, ref orphan_impl_items, ref paths, ref mut aliases, .. } =
-        *cache;
-
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
-    for &(did, ref item) in orphan_impl_items {
-        if let Some(&(ref fqp, _)) = paths.get(&did) {
-            search_index.push(IndexItem {
+    for &(did, ref item) in &cache.orphan_impl_items {
+        if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
+            cache.search_index.push(IndexItem {
                 ty: item.type_(),
                 name: item.name.unwrap().to_string(),
                 path: fqp[..fqp.len() - 1].join("::"),
                 desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(&item),
+                search_type: get_index_search_type(&item, None),
             });
             for alias in item.attrs.get_doc_aliases() {
-                aliases
+                cache
+                    .aliases
                     .entry(alias.to_lowercase())
                     .or_insert(Vec::new())
-                    .push(search_index.len() - 1);
+                    .push(cache.search_index.len() - 1);
             }
         }
     }
 
+    let Cache { ref mut search_index, ref paths, ref mut aliases, .. } = *cache;
+
     // Reduce `DefId` in paths into smaller sequential numbers,
     // and prune the paths that do not appear in the index.
     let mut lastpath = String::new();
@@ -164,7 +164,10 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     )
 }
 
-crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
+crate fn get_index_search_type(
+    item: &clean::Item,
+    cache: Option<&Cache>,
+) -> Option<IndexItemFunctionType> {
     let (all_types, ret_types) = match *item.kind {
         clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
         clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types),
@@ -174,12 +177,12 @@ crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionTy
 
     let inputs = all_types
         .iter()
-        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty, &cache), *kind)))
         .filter(|a| a.ty.name.is_some())
         .collect();
     let output = ret_types
         .iter()
-        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty, &cache), *kind)))
         .filter(|a| a.ty.name.is_some())
         .collect::<Vec<_>>();
     let output = if output.is_empty() { None } else { Some(output) };
@@ -187,12 +190,12 @@ crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionTy
     Some(IndexItemFunctionType { inputs, output })
 }
 
-fn get_index_type(clean_type: &clean::Type) -> RenderType {
+fn get_index_type(clean_type: &clean::Type, cache: &Option<&Cache>) -> RenderType {
     RenderType {
-        ty: clean_type.def_id(),
+        ty: cache.map_or_else(|| clean_type.def_id(), |cache| clean_type.def_id_full(cache)),
         idx: None,
         name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
-        generics: get_generics(clean_type),
+        generics: get_generics(clean_type, cache),
     }
 }
 
@@ -216,14 +219,14 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
     }
 }
 
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<Generic>> {
+fn get_generics(clean_type: &clean::Type, cache: &Option<&Cache>) -> Option<Vec<Generic>> {
     clean_type.generics().and_then(|types| {
         let r = types
             .iter()
             .filter_map(|t| {
                 get_index_type_name(t, false).map(|name| Generic {
                     name: name.as_str().to_ascii_lowercase(),
-                    defid: t.def_id(),
+                    defid: cache.map_or_else(|| t.def_id(), |cache| t.def_id_full(cache)),
                     idx: None,
                 })
             })
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ef45c98e406..bb9a7be590e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -69,7 +69,7 @@ use crate::clean::{self, AttributesExt, GetDefId, RenderedLink, SelfTy, TypeKind
 use crate::config::{RenderInfo, RenderOptions};
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
-use crate::formats::cache::{cache, Cache};
+use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode};
 use crate::html::escape::Escape;
@@ -122,6 +122,7 @@ crate struct Context<'tcx> {
     /// Storage for the errors produced while generating documentation so they
     /// can be printed together at the end.
     crate errors: Rc<Receiver<String>>,
+    crate cache: Rc<Cache>,
 }
 
 crate struct SharedContext<'tcx> {
@@ -392,7 +393,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         options: RenderOptions,
         _render_info: RenderInfo,
         edition: Edition,
-        cache: &mut Cache,
+        mut cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         // need to save a copy of the options for rendering the index page
@@ -503,9 +504,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         krate = sources::render(&dst, &mut scx, krate)?;
 
         // Build our search index
-        let index = build_index(&krate, cache);
+        let index = build_index(&krate, &mut cache);
 
-        let cache = Arc::new(cache);
         let mut cx = Context {
             current: Vec::new(),
             dst,
@@ -515,13 +515,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             shared: Arc::new(scx),
             all: Rc::new(RefCell::new(AllTypes::new())),
             errors: Rc::new(receiver),
+            cache: Rc::new(cache),
         };
 
         CURRENT_DEPTH.with(|s| s.set(0));
 
         // Write shared runs within a flock; disable thread dispatching of IO temporarily.
         Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
-        write_shared(&cx, &krate, index, &md_opts, &cache)?;
+        write_shared(&cx, &krate, index, &md_opts)?;
         Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
         Ok((cx, krate))
     }
@@ -529,7 +530,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
     fn after_krate(
         &mut self,
         krate: &clean::Crate,
-        cache: &Cache,
         diag: &rustc_errors::Handler,
     ) -> Result<(), Error> {
         let final_file = self.dst.join(&*krate.name.as_str()).join("all.html");
@@ -551,7 +551,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             extra_scripts: &[],
             static_extra_scripts: &[],
         };
-        let sidebar = if let Some(ref version) = cache.crate_version {
+        let sidebar = if let Some(ref version) = self.cache.crate_version {
             format!(
                 "<p class=\"location\">Crate {}</p>\
                      <div class=\"block version\">\
@@ -605,12 +605,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         }
     }
 
-    fn mod_item_in(
-        &mut self,
-        item: &clean::Item,
-        item_name: &str,
-        cache: &Cache,
-    ) -> Result<(), Error> {
+    fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error> {
         // Stripped modules survive the rustdoc passes (i.e., `strip-private`)
         // if they contain impls for public types. These modules can also
         // contain items such as publicly re-exported structures.
@@ -627,7 +622,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
 
         info!("Recursing into {}", self.dst.display());
 
-        let buf = self.render_item(item, false, cache);
+        let buf = self.render_item(item, false);
         // buf will be empty if the module is stripped and there is no redirect for it
         if !buf.is_empty() {
             self.shared.ensure_dir(&self.dst)?;
@@ -658,7 +653,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         Ok(())
     }
 
-    fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> {
+    fn item(&mut self, item: clean::Item) -> Result<(), Error> {
         // Stripped modules survive the rustdoc passes (i.e., `strip-private`)
         // if they contain impls for public types. These modules can also
         // contain items such as publicly re-exported structures.
@@ -670,7 +665,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             self.render_redirect_pages = item.is_stripped();
         }
 
-        let buf = self.render_item(&item, true, cache);
+        let buf = self.render_item(&item, true);
         // buf will be empty if the item is stripped and there is no redirect for it
         if !buf.is_empty() {
             let name = item.name.as_ref().unwrap();
@@ -694,6 +689,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         }
         Ok(())
     }
+
+    fn cache(&self) -> &Cache {
+        &self.cache
+    }
 }
 
 fn write_shared(
@@ -701,7 +700,6 @@ fn write_shared(
     krate: &clean::Crate,
     search_index: String,
     options: &RenderOptions,
-    cache: &Cache,
 ) -> Result<(), Error> {
     // Write out the shared files. Note that these are shared among all rustdoc
     // docs placed in the output directory, so this needs to be a synchronized
@@ -1107,7 +1105,7 @@ themePicker.onblur = handleThemeButtonsBlur;
 
     // Update the list of all implementors for traits
     let dst = cx.dst.join("implementors");
-    for (&did, imps) in &cache.implementors {
+    for (&did, imps) in &cx.cache.implementors {
         // Private modules can leak through to this phase of rustdoc, which
         // could contain implementations for otherwise private types. In some
         // rare cases we could find an implementation for an item which wasn't
@@ -1115,9 +1113,9 @@ themePicker.onblur = handleThemeButtonsBlur;
         //
         // FIXME: this is a vague explanation for why this can't be a `get`, in
         //        theory it should be...
-        let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) {
+        let &(ref remote_path, remote_item_type) = match cx.cache.paths.get(&did) {
             Some(p) => p,
-            None => match cache.external_paths.get(&did) {
+            None => match cx.cache.external_paths.get(&did) {
                 Some(p) => p,
                 None => continue,
             },
@@ -1144,9 +1142,9 @@ themePicker.onblur = handleThemeButtonsBlur;
                     None
                 } else {
                     Some(Implementor {
-                        text: imp.inner_impl().print().to_string(),
+                        text: imp.inner_impl().print(cx.cache()).to_string(),
                         synthetic: imp.inner_impl().synthetic,
-                        types: collect_paths_for_type(imp.inner_impl().for_.clone()),
+                        types: collect_paths_for_type(imp.inner_impl().for_.clone(), cx.cache()),
                     })
                 }
             })
@@ -1155,7 +1153,7 @@ themePicker.onblur = handleThemeButtonsBlur;
         // Only create a js file if we have impls to add to it. If the trait is
         // documented locally though we always create the file to avoid dead
         // links.
-        if implementors.is_empty() && !cache.paths.contains_key(&did) {
+        if implementors.is_empty() && !cx.cache.paths.contains_key(&did) {
             continue;
         }
 
@@ -1214,8 +1212,8 @@ fn write_minify(
     }
 }
 
-fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Cache) {
-    if let Some(l) = cx.src_href(item, cache) {
+fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
+    if let Some(l) = cx.src_href(item) {
         write!(
             buf,
             "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
@@ -1537,7 +1535,7 @@ impl Context<'_> {
         "../".repeat(self.current.len())
     }
 
-    fn render_item(&self, it: &clean::Item, pushname: bool, cache: &Cache) -> String {
+    fn render_item(&self, it: &clean::Item, pushname: bool) -> String {
         // A little unfortunate that this is done like this, but it sure
         // does make formatting *a lot* nicer.
         CURRENT_DEPTH.with(|slot| {
@@ -1590,13 +1588,13 @@ impl Context<'_> {
             layout::render(
                 &self.shared.layout,
                 &page,
-                |buf: &mut _| print_sidebar(self, it, buf, cache),
-                |buf: &mut _| print_item(self, it, buf, cache),
+                |buf: &mut _| print_sidebar(self, it, buf),
+                |buf: &mut _| print_item(self, it, buf),
                 &self.shared.style_files,
             )
         } else {
             let mut url = self.root_path();
-            if let Some(&(ref names, ty)) = cache.paths.get(&it.def_id) {
+            if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
                 for name in &names[..names.len() - 1] {
                     url.push_str(name);
                     url.push('/');
@@ -1647,7 +1645,7 @@ impl Context<'_> {
     /// If `None` is returned, then a source link couldn't be generated. This
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
-    fn src_href(&self, item: &clean::Item, cache: &Cache) -> Option<String> {
+    fn src_href(&self, item: &clean::Item) -> Option<String> {
         let mut root = self.root_path();
         let mut path = String::new();
         let cnum = item.source.cnum(self.sess());
@@ -1667,7 +1665,7 @@ impl Context<'_> {
                 return None;
             }
         } else {
-            let (krate, src_root) = match *cache.extern_locations.get(&cnum)? {
+            let (krate, src_root) = match *self.cache.extern_locations.get(&cnum)? {
                 (name, ref src, ExternalLocation::Local) => (name, src),
                 (name, ref src, ExternalLocation::Remote(ref s)) => {
                     root = s.to_string();
@@ -1710,7 +1708,7 @@ where
     write!(w, "</div>")
 }
 
-fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Cache) {
+fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
     debug_assert!(!item.is_stripped());
     // Write the breadcrumb trail header for the top
     write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
@@ -1738,7 +1736,7 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca
     // this page, and this link will be auto-clicked. The `id` attribute is
     // used to find the link to auto-click.
     if cx.shared.include_sources && !item.is_primitive() {
-        write_srclink(cx, item, buf, cache);
+        write_srclink(cx, item, buf);
     }
 
     write!(buf, "</span>"); // out-of-band
@@ -1797,20 +1795,20 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca
         clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
             item_function(buf, cx, item, f)
         }
-        clean::TraitItem(ref t) => item_trait(buf, cx, item, t, cache),
-        clean::StructItem(ref s) => item_struct(buf, cx, item, s, cache),
-        clean::UnionItem(ref s) => item_union(buf, cx, item, s, cache),
-        clean::EnumItem(ref e) => item_enum(buf, cx, item, e, cache),
-        clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t, cache),
+        clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
+        clean::StructItem(ref s) => item_struct(buf, cx, item, s),
+        clean::UnionItem(ref s) => item_union(buf, cx, item, s),
+        clean::EnumItem(ref e) => item_enum(buf, cx, item, e),
+        clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t),
         clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
         clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
-        clean::PrimitiveItem(_) => item_primitive(buf, cx, item, cache),
+        clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
         clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i),
         clean::ConstantItem(ref c) => item_constant(buf, cx, item, c),
-        clean::ForeignTypeItem => item_foreign_type(buf, cx, item, cache),
+        clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
         clean::KeywordItem(_) => item_keyword(buf, cx, item),
-        clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e, cache),
-        clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta, cache),
+        clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e),
+        clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta),
         _ => {
             // We don't generate pages for any other type.
             unreachable!();
@@ -1884,10 +1882,11 @@ fn document_short(
         return;
     }
     if let Some(s) = item.doc_value() {
-        let mut summary_html = MarkdownSummaryLine(&s, &item.links()).into_string();
+        let mut summary_html = MarkdownSummaryLine(&s, &item.links(&cx.cache)).into_string();
 
         if s.contains('\n') {
-            let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link));
+            let link =
+                format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx.cache()));
 
             if let Some(idx) = summary_html.rfind("</p>") {
                 summary_html.insert_str(idx, &link);
@@ -1922,7 +1921,7 @@ fn document_full(
 ) {
     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
         debug!("Doc block: =====\n{}\n=====", s);
-        render_markdown(w, cx, &*s, item.links(), prefix, is_hidden);
+        render_markdown(w, cx, &*s, item.links(&cx.cache), prefix, is_hidden);
     } else if !prefix.is_empty() {
         write!(
             w,
@@ -2161,15 +2160,15 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     Some(ref src) => write!(
                         w,
                         "<tr><td><code>{}extern crate {} as {};",
-                        myitem.visibility.print_with_space(cx.tcx(), myitem.def_id),
-                        anchor(myitem.def_id, &*src.as_str()),
+                        myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()),
+                        anchor(myitem.def_id, &*src.as_str(), cx.cache()),
                         name
                     ),
                     None => write!(
                         w,
                         "<tr><td><code>{}extern crate {};",
-                        myitem.visibility.print_with_space(cx.tcx(), myitem.def_id),
-                        anchor(myitem.def_id, &*name.as_str())
+                        myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()),
+                        anchor(myitem.def_id, &*name.as_str(), cx.cache())
                     ),
                 }
                 write!(w, "</code></td></tr>");
@@ -2179,8 +2178,8 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                 write!(
                     w,
                     "<tr><td><code>{}{}</code></td></tr>",
-                    myitem.visibility.print_with_space(cx.tcx(), myitem.def_id),
-                    import.print()
+                    myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()),
+                    import.print(cx.cache())
                 );
             }
 
@@ -2211,7 +2210,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                      </tr>",
                     name = *myitem.name.as_ref().unwrap(),
                     stab_tags = extra_info_tags(myitem, item, cx.tcx()),
-                    docs = MarkdownSummaryLine(&doc_value, &myitem.links()).into_string(),
+                    docs = MarkdownSummaryLine(&doc_value, &myitem.links(&cx.cache)).into_string(),
                     class = myitem.type_(),
                     add = add,
                     stab = stab.unwrap_or_else(String::new),
@@ -2396,9 +2395,9 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
     write!(
         w,
         "{vis}const {name}: {typ}",
-        vis = it.visibility.print_with_space(cx.tcx(), it.def_id),
+        vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         name = it.name.as_ref().unwrap(),
-        typ = c.type_.print(),
+        typ = c.type_.print(cx.cache()),
     );
 
     if c.value.is_some() || c.is_literal {
@@ -2430,10 +2429,10 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
     write!(
         w,
         "{vis}static {mutability}{name}: {typ}</pre>",
-        vis = it.visibility.print_with_space(cx.tcx(), it.def_id),
+        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()
+        typ = s.type_.print(cx.cache())
     );
     document(w, cx, it, None)
 }
@@ -2441,13 +2440,13 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
 fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
     let header_len = format!(
         "{}{}{}{}{:#}fn {}{:#}",
-        it.visibility.print_with_space(cx.tcx(), it.def_id),
+        it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         f.header.constness.print_with_space(),
         f.header.asyncness.print_with_space(),
         f.header.unsafety.print_with_space(),
         print_abi_with_space(f.header.abi),
         it.name.as_ref().unwrap(),
-        f.generics.print()
+        f.generics.print(cx.cache())
     )
     .len();
     write!(w, "<pre class=\"rust fn\">");
@@ -2456,17 +2455,18 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         w,
         "{vis}{constness}{asyncness}{unsafety}{abi}fn \
          {name}{generics}{decl}{spotlight}{where_clause}</pre>",
-        vis = it.visibility.print_with_space(cx.tcx(), it.def_id),
+        vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         constness = f.header.constness.print_with_space(),
         asyncness = f.header.asyncness.print_with_space(),
         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(),
-        where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
+        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(),
-        spotlight = spotlight_decl(&f.decl),
+            .print(cx.cache()),
+        spotlight = spotlight_decl(&f.decl, cx.cache()),
     );
     document(w, cx, it, None)
 }
@@ -2478,7 +2478,6 @@ fn render_implementor(
     w: &mut Buffer,
     implementor_dups: &FxHashMap<Symbol, (DefId, bool)>,
     aliases: &[String],
-    cache: &Cache,
 ) {
     // If there's already another implementor that has the same abbridged name, use the
     // full path, for example in `std::iter::ExactSizeIterator`
@@ -2504,7 +2503,6 @@ fn render_implementor(
         false,
         false,
         aliases,
-        cache,
     );
 }
 
@@ -2513,12 +2511,11 @@ fn render_impls(
     w: &mut Buffer,
     traits: &[&&Impl],
     containing_item: &clean::Item,
-    cache: &Cache,
 ) {
     let mut impls = traits
         .iter()
         .map(|i| {
-            let did = i.trait_did().unwrap();
+            let did = i.trait_did_full(cx.cache()).unwrap();
             let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
             render_impl(
@@ -2535,7 +2532,6 @@ fn render_impls(
                 false,
                 true,
                 &[],
-                cache,
             );
             buffer.into_inner()
         })
@@ -2544,7 +2540,7 @@ fn render_impls(
     w.write_str(&impls.join(""));
 }
 
-fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
+fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cache: &Cache) -> String {
     let mut bounds = String::new();
     if !t_bounds.is_empty() {
         if !trait_alias {
@@ -2554,22 +2550,22 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
             if i > 0 {
                 bounds.push_str(" + ");
             }
-            bounds.push_str(&p.print().to_string());
+            bounds.push_str(&p.print(cache).to_string());
         }
     }
     bounds
 }
 
-fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
-    let lhs = format!("{}", lhs.inner_impl().print());
-    let rhs = format!("{}", rhs.inner_impl().print());
+fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cache: &Cache) -> Ordering {
+    let lhs = format!("{}", lhs.inner_impl().print(cache));
+    let rhs = format!("{}", rhs.inner_impl().print(cache));
 
     // lhs and rhs are formatted as HTML, which may be unnecessary
     compare_names(&lhs, &rhs)
 }
 
-fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait, cache: &Cache) {
-    let bounds = bounds(&t.bounds, false);
+fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
+    let bounds = bounds(&t.bounds, false, cx.cache());
     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<_>>();
@@ -2582,16 +2578,17 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         write!(
             w,
             "{}{}{}trait {}{}{}",
-            it.visibility.print_with_space(cx.tcx(), it.def_id),
+            it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
             t.unsafety.print_with_space(),
             if t.is_auto { "auto " } else { "" },
             it.name.as_ref().unwrap(),
-            t.generics.print(),
+            t.generics.print(cx.cache()),
             bounds
         );
 
         if !t.generics.where_predicates.is_empty() {
-            write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true });
+            let where_ = WhereClause { gens: &t.generics, indent: 0, end_newline: true };
+            write!(w, "{}", where_.print(cx.cache()));
         } else {
             write!(w, " ");
         }
@@ -2664,13 +2661,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         write!(w, "{}<span class=\"loading-content\">Loading content...</span>", extra_content)
     }
 
-    fn trait_item(
-        w: &mut Buffer,
-        cx: &Context<'_>,
-        m: &clean::Item,
-        t: &clean::Item,
-        cache: &Cache,
-    ) {
+    fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
         let name = m.name.as_ref().unwrap();
         info!("Documenting {} on {:?}", name, t.name);
         let item_type = m.type_();
@@ -2679,7 +2670,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
         write!(w, "</code>");
         render_stability_since(w, m, t, cx.tcx());
-        write_srclink(cx, m, w, cache);
+        write_srclink(cx, m, w);
         write!(w, "</h3>");
         document(w, cx, m, Some(t));
     }
@@ -2692,7 +2683,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             "<div class=\"methods\">",
         );
         for t in types {
-            trait_item(w, cx, t, it, cache);
+            trait_item(w, cx, t, it);
         }
         write_loading_content(w, "</div>");
     }
@@ -2705,7 +2696,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             "<div class=\"methods\">",
         );
         for t in consts {
-            trait_item(w, cx, t, it, cache);
+            trait_item(w, cx, t, it);
         }
         write_loading_content(w, "</div>");
     }
@@ -2719,7 +2710,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             "<div class=\"methods\">",
         );
         for m in required {
-            trait_item(w, cx, m, it, cache);
+            trait_item(w, cx, m, it);
         }
         write_loading_content(w, "</div>");
     }
@@ -2731,15 +2722,15 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             "<div class=\"methods\">",
         );
         for m in provided {
-            trait_item(w, cx, m, it, cache);
+            trait_item(w, cx, m, it);
         }
         write_loading_content(w, "</div>");
     }
 
     // If there are methods directly on this trait object, render them here.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache);
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All);
 
-    if let Some(implementors) = cache.implementors.get(&it.def_id) {
+    if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
         // The DefId is for the first Type found with that name. The bool is
         // if any Types with the same name but different DefId have been found.
         let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
@@ -2761,14 +2752,17 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         }
 
         let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
-            i.inner_impl().for_.def_id().map_or(true, |d| cache.paths.contains_key(&d))
+            i.inner_impl()
+                .for_
+                .def_id_full(cx.cache())
+                .map_or(true, |d| cx.cache.paths.contains_key(&d))
         });
 
         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
             local.iter().partition(|i| i.inner_impl().synthetic);
 
-        synthetic.sort_by(compare_impl);
-        concrete.sort_by(compare_impl);
+        synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache()));
+        concrete.sort_by(|a, b| compare_impl(a, b, cx.cache()));
 
         if !foreign.is_empty() {
             write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
@@ -2792,7 +2786,6 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                     true,
                     false,
                     &[],
-                    cache,
                 );
             }
             write_loading_content(w, "");
@@ -2805,7 +2798,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             "<div class=\"item-list\" id=\"implementors-list\">",
         );
         for implementor in concrete {
-            render_implementor(cx, implementor, it, w, &implementor_dups, &[], cache);
+            render_implementor(cx, implementor, it, w, &implementor_dups, &[]);
         }
         write_loading_content(w, "</div>");
 
@@ -2823,8 +2816,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                     it,
                     w,
                     &implementor_dups,
-                    &collect_paths_for_type(implementor.inner_impl().for_.clone()),
-                    cache,
+                    &collect_paths_for_type(implementor.inner_impl().for_.clone(), &cx.cache),
                 );
             }
             write_loading_content(w, "</div>");
@@ -2860,7 +2852,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         path = if it.def_id.is_local() {
             cx.current.join("/")
         } else {
-            let (ref path, _) = cache.external_paths[&it.def_id];
+            let (ref path, _) = cx.cache.external_paths[&it.def_id];
             path[..path.len() - 1].join("/")
         },
         ty = it.type_(),
@@ -2868,7 +2860,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
     );
 }
 
-fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String {
+fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cache: &Cache) -> String {
     use crate::formats::item_type::ItemType::*;
 
     let name = it.name.as_ref().unwrap();
@@ -2882,7 +2874,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String {
         AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
         AssocItemLink::Anchor(None) => anchor,
         AssocItemLink::GotoSource(did, _) => {
-            href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
+            href(did, cache).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
         }
     }
 }
@@ -2900,10 +2892,10 @@ fn assoc_const(
         w,
         "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
         extra,
-        it.visibility.print_with_space(cx.tcx(), it.def_id),
-        naive_assoc_href(it, link),
+        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()
+        ty.print(cx.cache())
     );
 }
 
@@ -2914,19 +2906,20 @@ fn assoc_type(
     default: Option<&clean::Type>,
     link: AssocItemLink<'_>,
     extra: &str,
+    cache: &Cache,
 ) {
     write!(
         w,
         "{}type <a href=\"{}\" class=\"type\">{}</a>",
         extra,
-        naive_assoc_href(it, link),
+        naive_assoc_href(it, link, cache),
         it.name.as_ref().unwrap()
     );
     if !bounds.is_empty() {
-        write!(w, ": {}", print_generic_bounds(bounds))
+        write!(w, ": {}", print_generic_bounds(bounds, cache))
     }
     if let Some(default) = default {
-        write!(w, " = {}", default.print())
+        write!(w, " = {}", default.print(cache))
     }
 }
 
@@ -3005,19 +2998,19 @@ fn render_assoc_item(
                     ItemType::TyMethod
                 };
 
-                href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
+                href(did, cx.cache()).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
         let mut header_len = format!(
             "{}{}{}{}{}{:#}fn {}{:#}",
-            meth.visibility.print_with_space(cx.tcx(), meth.def_id),
+            meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()),
             header.constness.print_with_space(),
             header.asyncness.print_with_space(),
             header.unsafety.print_with_space(),
             print_default_space(meth.is_default()),
             print_abi_with_space(header.abi),
             name,
-            g.print()
+            g.print(cx.cache())
         )
         .len();
         let (indent, end_newline) = if parent == ItemType::Trait {
@@ -3032,7 +3025,7 @@ fn render_assoc_item(
             "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
              {generics}{decl}{spotlight}{where_clause}",
             if parent == ItemType::Trait { "    " } else { "" },
-            meth.visibility.print_with_space(cx.tcx(), meth.def_id),
+            meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()),
             header.constness.print_with_space(),
             header.asyncness.print_with_space(),
             header.unsafety.print_with_space(),
@@ -3040,10 +3033,11 @@ fn render_assoc_item(
             print_abi_with_space(header.abi),
             href = href,
             name = name,
-            generics = g.print(),
-            decl = Function { decl: d, header_len, indent, asyncness: header.asyncness }.print(),
-            spotlight = spotlight_decl(&d),
-            where_clause = WhereClause { gens: g, indent, end_newline }
+            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())
         )
     }
     match *item.kind {
@@ -3070,18 +3064,13 @@ fn render_assoc_item(
             default.as_ref(),
             link,
             if parent == ItemType::Trait { "    " } else { "" },
+            cx.cache(),
         ),
         _ => panic!("render_assoc_item called on non-associated-item"),
     }
 }
 
-fn item_struct(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    it: &clean::Item,
-    s: &clean::Struct,
-    cache: &Cache,
-) {
+fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class=\"rust struct\">");
         render_attributes(w, it, true);
@@ -3122,16 +3111,16 @@ fn item_struct(
                     item_type = ItemType::StructField,
                     id = id,
                     name = field.name.as_ref().unwrap(),
-                    ty = ty.print()
+                    ty = ty.print(cx.cache())
                 );
                 document(w, cx, field, Some(it));
             }
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union, cache: &Cache) {
+fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class=\"rust union\">");
         render_attributes(w, it, true);
@@ -3166,7 +3155,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()
+                ty = ty.print(cx.cache())
             );
             if let Some(stability_class) = field.stability_class(cx.tcx()) {
                 write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
@@ -3174,20 +3163,20 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             document(w, cx, field, Some(it));
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum, cache: &Cache) {
+fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class=\"rust enum\">");
         render_attributes(w, it, true);
         write!(
             w,
             "{}enum {}{}{}",
-            it.visibility.print_with_space(cx.tcx(), it.def_id),
+            it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
             it.name.as_ref().unwrap(),
-            e.generics.print(),
-            WhereClause { gens: &e.generics, indent: 0, end_newline: true }
+            e.generics.print(cx.cache()),
+            WhereClause { gens: &e.generics, indent: 0, end_newline: true }.print(cx.cache())
         );
         if e.variants.is_empty() && !e.variants_stripped {
             write!(w, " {{}}");
@@ -3205,7 +3194,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                                 if i > 0 {
                                     write!(w, ",&nbsp;")
                                 }
-                                write!(w, "{}", ty.print());
+                                write!(w, "{}", ty.print(cx.cache()));
                             }
                             write!(w, ")");
                         }
@@ -3252,7 +3241,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                     if i > 0 {
                         write!(w, ",&nbsp;");
                     }
-                    write!(w, "{}", ty.print());
+                    write!(w, "{}", ty.print(cx.cache()));
                 }
                 write!(w, ")");
             }
@@ -3289,7 +3278,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()
+                            t = ty.print(cx.cache())
                         );
                         document(w, cx, field, Some(variant));
                     }
@@ -3299,7 +3288,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             render_stability_since(w, variant, it, cx.tcx());
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
 const ALLOWED_ATTRIBUTES: &[Symbol] = &[
@@ -3357,17 +3346,21 @@ fn render_struct(
     write!(
         w,
         "{}{}{}",
-        it.visibility.print_with_space(cx.tcx(), it.def_id),
+        it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         if structhead { "struct " } else { "" },
         it.name.as_ref().unwrap()
     );
     if let Some(g) = g {
-        write!(w, "{}", g.print())
+        write!(w, "{}", g.print(cx.cache()))
     }
     match ty {
         CtorKind::Fictive => {
             if let Some(g) = g {
-                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })
+                write!(
+                    w,
+                    "{}",
+                    WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache())
+                )
             }
             let mut has_visible_fields = false;
             write!(w, " {{");
@@ -3377,9 +3370,9 @@ fn render_struct(
                         w,
                         "\n{}    {}{}: {},",
                         tab,
-                        field.visibility.print_with_space(cx.tcx(), field.def_id),
+                        field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
                         field.name.as_ref().unwrap(),
-                        ty.print()
+                        ty.print(cx.cache())
                     );
                     has_visible_fields = true;
                 }
@@ -3409,8 +3402,8 @@ fn render_struct(
                         write!(
                             w,
                             "{}{}",
-                            field.visibility.print_with_space(cx.tcx(), field.def_id),
-                            ty.print()
+                            field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
+                            ty.print(cx.cache())
                         )
                     }
                     _ => unreachable!(),
@@ -3418,14 +3411,22 @@ fn render_struct(
             }
             write!(w, ")");
             if let Some(g) = g {
-                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })
+                write!(
+                    w,
+                    "{}",
+                    WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache())
+                )
             }
             write!(w, ";");
         }
         CtorKind::Const => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })
+                write!(
+                    w,
+                    "{}",
+                    WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache())
+                )
             }
             write!(w, ";");
         }
@@ -3444,13 +3445,13 @@ fn render_union(
     write!(
         w,
         "{}{}{}",
-        it.visibility.print_with_space(cx.tcx(), it.def_id),
+        it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         if structhead { "union " } else { "" },
         it.name.as_ref().unwrap()
     );
     if let Some(g) = g {
-        write!(w, "{}", g.print());
-        write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true });
+        write!(w, "{}", g.print(cx.cache()));
+        write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache()));
     }
 
     write!(w, " {{\n{}", tab);
@@ -3459,9 +3460,9 @@ fn render_union(
             write!(
                 w,
                 "    {}{}: {},\n{}",
-                field.visibility.print_with_space(cx.tcx(), field.def_id),
+                field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
                 field.name.as_ref().unwrap(),
-                ty.print(),
+                ty.print(cx.cache()),
                 tab
             );
         }
@@ -3494,10 +3495,9 @@ fn render_assoc_items(
     containing_item: &clean::Item,
     it: DefId,
     what: AssocItemRender<'_>,
-    cache: &Cache,
 ) {
     info!("Documenting associated items of {:?}", containing_item.name);
-    let v = match cache.impls.get(&it) {
+    let v = match cx.cache.impls.get(&it) {
         Some(v) => v,
         None => return,
     };
@@ -3514,9 +3514,13 @@ fn render_assoc_items(
                 RenderMode::Normal
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
-                let id =
-                    cx.derive_id(small_url_encode(&format!("deref-methods-{:#}", type_.print())));
-                cx.deref_id_map.borrow_mut().insert(type_.def_id().unwrap(), id.clone());
+                let id = cx.derive_id(small_url_encode(&format!(
+                    "deref-methods-{:#}",
+                    type_.print(cx.cache())
+                )));
+                cx.deref_id_map
+                    .borrow_mut()
+                    .insert(type_.def_id_full(cx.cache()).unwrap(), id.clone());
                 write!(
                     w,
                     "<h2 id=\"{id}\" class=\"small-section-header\">\
@@ -3524,8 +3528,8 @@ fn render_assoc_items(
                          <a href=\"#{id}\" class=\"anchor\"></a>\
                      </h2>",
                     id = id,
-                    trait_ = trait_.print(),
-                    type_ = type_.print(),
+                    trait_ = trait_.print(cx.cache()),
+                    type_ = type_.print(cx.cache()),
                 );
                 RenderMode::ForDeref { mut_: deref_mut_ }
             }
@@ -3545,17 +3549,18 @@ fn render_assoc_items(
                 false,
                 true,
                 &[],
-                cache,
             );
         }
     }
     if !traits.is_empty() {
-        let deref_impl =
-            traits.iter().find(|t| t.inner_impl().trait_.def_id() == cache.deref_trait_did);
+        let deref_impl = traits
+            .iter()
+            .find(|t| t.inner_impl().trait_.def_id_full(cx.cache()) == cx.cache.deref_trait_did);
         if let Some(impl_) = deref_impl {
-            let has_deref_mut =
-                traits.iter().any(|t| t.inner_impl().trait_.def_id() == cache.deref_mut_trait_did);
-            render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, cache);
+            let has_deref_mut = traits.iter().any(|t| {
+                t.inner_impl().trait_.def_id_full(cx.cache()) == cx.cache.deref_mut_trait_did
+            });
+            render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
         }
 
         // If we were already one level into rendering deref methods, we don't want to render
@@ -3570,7 +3575,7 @@ fn render_assoc_items(
             concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
 
         let mut impls = Buffer::empty_from(&w);
-        render_impls(cx, &mut impls, &concrete, containing_item, cache);
+        render_impls(cx, &mut impls, &concrete, containing_item);
         let impls = impls.into_inner();
         if !impls.is_empty() {
             write!(
@@ -3592,7 +3597,7 @@ fn render_assoc_items(
                  </h2>\
                  <div id=\"synthetic-implementations-list\">"
             );
-            render_impls(cx, w, &synthetic, containing_item, cache);
+            render_impls(cx, w, &synthetic, containing_item);
             write!(w, "</div>");
         }
 
@@ -3605,7 +3610,7 @@ fn render_assoc_items(
                  </h2>\
                  <div id=\"blanket-implementations-list\">"
             );
-            render_impls(cx, w, &blanket_impl, containing_item, cache);
+            render_impls(cx, w, &blanket_impl, containing_item);
             write!(w, "</div>");
         }
     }
@@ -3617,7 +3622,6 @@ fn render_deref_methods(
     impl_: &Impl,
     container_item: &clean::Item,
     deref_mut: bool,
-    cache: &Cache,
 ) {
     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
     let (target, real_target) = impl_
@@ -3634,25 +3638,25 @@ fn render_deref_methods(
         .expect("Expected associated type binding");
     let what =
         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
-    if let Some(did) = target.def_id() {
-        if let Some(type_did) = impl_.inner_impl().for_.def_id() {
+    if let Some(did) = target.def_id_full(cx.cache()) {
+        if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) {
             // `impl Deref<Target = S> for S`
             if did == type_did {
                 // Avoid infinite cycles
                 return;
             }
         }
-        render_assoc_items(w, cx, container_item, did, what, cache);
+        render_assoc_items(w, cx, container_item, did, what);
     } else {
         if let Some(prim) = target.primitive_type() {
-            if let Some(&did) = cache.primitive_locations.get(&prim) {
-                render_assoc_items(w, cx, container_item, did, what, cache);
+            if let Some(&did) = cx.cache.primitive_locations.get(&prim) {
+                render_assoc_items(w, cx, container_item, did, what);
             }
         }
     }
 }
 
-fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
+fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool {
     let self_type_opt = match *item.kind {
         clean::MethodItem(ref method, _) => method.decl.self_type(),
         clean::TyMethodItem(ref method) => method.decl.self_type(),
@@ -3666,7 +3670,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
                 (mutability == Mutability::Mut, false, false)
             }
             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
-                (false, Some(did) == cache().owned_box_did, false)
+                (false, Some(did) == cache.owned_box_did, false)
             }
             SelfTy::SelfValue => (false, false, true),
             _ => (false, false, false),
@@ -3678,31 +3682,31 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
     }
 }
 
-fn spotlight_decl(decl: &clean::FnDecl) -> String {
+fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String {
     let mut out = Buffer::html();
     let mut trait_ = String::new();
 
-    if let Some(did) = decl.output.def_id() {
-        let c = cache();
-        if let Some(impls) = c.impls.get(&did) {
+    if let Some(did) = decl.output.def_id_full(cache) {
+        if let Some(impls) = cache.impls.get(&did) {
             for i in impls {
                 let impl_ = i.inner_impl();
-                if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
+                if impl_.trait_.def_id_full(cache).map_or(false, |d| cache.traits[&d].is_spotlight)
+                {
                     if out.is_empty() {
                         out.push_str(&format!(
                             "<h3 class=\"notable\">Notable traits for {}</h3>\
                              <code class=\"content\">",
-                            impl_.for_.print()
+                            impl_.for_.print(cache)
                         ));
-                        trait_.push_str(&impl_.for_.print().to_string());
+                        trait_.push_str(&impl_.for_.print(cache).to_string());
                     }
 
                     //use the "where" class here to make it small
                     out.push_str(&format!(
                         "<span class=\"where fmt-newline\">{}</span>",
-                        impl_.print()
+                        impl_.print(cache)
                     ));
-                    let t_did = impl_.trait_.def_id().unwrap();
+                    let t_did = impl_.trait_.def_id_full(cache).unwrap();
                     for it in &impl_.items {
                         if let clean::TypedefItem(ref tydef, _) = *it.kind {
                             out.push_str("<span class=\"where fmt-newline\">    ");
@@ -3713,6 +3717,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
                                 Some(&tydef.type_),
                                 AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
                                 "",
+                                cache,
                             );
                             out.push_str(";</span>");
                         }
@@ -3750,18 +3755,17 @@ fn render_impl(
     // This argument is used to reference same type with different paths to avoid duplication
     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
     aliases: &[String],
-    cache: &Cache,
 ) {
-    let traits = &cache.traits;
-    let trait_ = i.trait_did().map(|did| &traits[&did]);
+    let traits = &cx.cache.traits;
+    let trait_ = i.trait_did_full(cx.cache()).map(|did| &traits[&did]);
 
     if render_mode == RenderMode::Normal {
         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)
+                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx.cache())
                 } else {
-                    format!("impl-{}", small_url_encode(&format!("{:#}", t.print())))
+                    format!("impl-{}", small_url_encode(&format!("{:#}", t.print(cx.cache()))))
                 }
             }
             None => "impl".to_string(),
@@ -3773,12 +3777,20 @@ fn render_impl(
         };
         if let Some(use_absolute) = use_absolute {
             write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases);
-            fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
+            fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute, cx.cache());
             if show_def_docs {
                 for it in &i.inner_impl().items {
                     if let clean::TypedefItem(ref tydef, _) = *it.kind {
                         write!(w, "<span class=\"where fmt-newline\">  ");
-                        assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "");
+                        assoc_type(
+                            w,
+                            it,
+                            &[],
+                            Some(&tydef.type_),
+                            AssocItemLink::Anchor(None),
+                            "",
+                            cx.cache(),
+                        );
                         write!(w, ";</span>");
                     }
                 }
@@ -3790,7 +3802,7 @@ fn render_impl(
                 "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
                 id,
                 aliases,
-                i.inner_impl().print()
+                i.inner_impl().print(cx.cache())
             );
         }
         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -3801,7 +3813,7 @@ fn render_impl(
             outer_version,
             outer_const_version,
         );
-        write_srclink(cx, &i.impl_item, w, cache);
+        write_srclink(cx, &i.impl_item, w);
         write!(w, "</h3>");
 
         if trait_.is_some() {
@@ -3817,7 +3829,7 @@ fn render_impl(
                 "<div class=\"docblock\">{}</div>",
                 Markdown(
                     &*dox,
-                    &i.impl_item.links(),
+                    &i.impl_item.links(&cx.cache),
                     &mut ids,
                     cx.shared.codes,
                     cx.shared.edition,
@@ -3840,14 +3852,15 @@ fn render_impl(
         outer_const_version: Option<&str>,
         trait_: Option<&clean::Trait>,
         show_def_docs: bool,
-        cache: &Cache,
     ) {
         let item_type = item.type_();
         let name = item.name.as_ref().unwrap();
 
         let render_method_item = match render_mode {
             RenderMode::Normal => true,
-            RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
+            RenderMode::ForDeref { mut_: deref_mut_ } => {
+                should_render_item(&item, deref_mut_, &cx.cache)
+            }
         };
 
         let (is_hidden, extra_class) =
@@ -3874,14 +3887,22 @@ fn render_impl(
                         outer_version,
                         outer_const_version,
                     );
-                    write_srclink(cx, item, w, cache);
+                    write_srclink(cx, item, w);
                     write!(w, "</h4>");
                 }
             }
             clean::TypedefItem(ref tydef, _) => {
                 let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name));
                 write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
-                assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "");
+                assoc_type(
+                    w,
+                    item,
+                    &Vec::new(),
+                    Some(&tydef.type_),
+                    link.anchor(&id),
+                    "",
+                    cx.cache(),
+                );
                 write!(w, "</code></h4>");
             }
             clean::AssocConstItem(ref ty, ref default) => {
@@ -3896,13 +3917,13 @@ fn render_impl(
                     outer_version,
                     outer_const_version,
                 );
-                write_srclink(cx, item, w, cache);
+                write_srclink(cx, item, w);
                 write!(w, "</h4>");
             }
             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), "");
+                assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "", cx.cache());
                 write!(w, "</code></h4>");
             }
             clean::StrippedItem(..) => return,
@@ -3961,7 +3982,6 @@ fn render_impl(
             outer_const_version,
             trait_,
             show_def_docs,
-            cache,
         );
     }
 
@@ -3975,14 +3995,13 @@ fn render_impl(
         outer_version: Option<&str>,
         outer_const_version: Option<&str>,
         show_def_docs: bool,
-        cache: &Cache,
     ) {
         for trait_item in &t.items {
             let n = trait_item.name;
             if i.items.iter().any(|m| m.name == n) {
                 continue;
             }
-            let did = i.trait_.as_ref().unwrap().def_id().unwrap();
+            let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
             let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
 
             doc_impl_item(
@@ -3997,7 +4016,6 @@ fn render_impl(
                 outer_const_version,
                 None,
                 show_def_docs,
-                cache,
             );
         }
     }
@@ -4018,29 +4036,23 @@ fn render_impl(
                 outer_version,
                 outer_const_version,
                 show_def_docs,
-                cache,
             );
         }
     }
     write!(w, "</div>");
 }
 
-fn item_opaque_ty(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    it: &clean::Item,
-    t: &clean::OpaqueTy,
-    cache: &Cache,
-) {
+fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
     write!(w, "<pre class=\"rust opaque\">");
     render_attributes(w, it, false);
     write!(
         w,
         "type {}{}{where_clause} = impl {bounds};</pre>",
         it.name.as_ref().unwrap(),
-        t.generics.print(),
-        where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
-        bounds = bounds(&t.bounds, false)
+        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())
     );
 
     document(w, cx, it, None);
@@ -4049,25 +4061,19 @@ fn item_opaque_ty(
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn item_trait_alias(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    it: &clean::Item,
-    t: &clean::TraitAlias,
-    cache: &Cache,
-) {
+fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
     write!(w, "<pre class=\"rust trait-alias\">");
     render_attributes(w, it, false);
     write!(
         w,
         "trait {}{}{} = {};</pre>",
         it.name.as_ref().unwrap(),
-        t.generics.print(),
-        WhereClause { gens: &t.generics, indent: 0, end_newline: true },
-        bounds(&t.bounds, true)
+        t.generics.print(cx.cache()),
+        WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
+        bounds(&t.bounds, true, cx.cache())
     );
 
     document(w, cx, it, None);
@@ -4076,25 +4082,20 @@ fn item_trait_alias(
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn item_typedef(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    it: &clean::Item,
-    t: &clean::Typedef,
-    cache: &Cache,
-) {
+fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
     write!(w, "<pre class=\"rust typedef\">");
     render_attributes(w, it, false);
     write!(
         w,
         "type {}{}{where_clause} = {type_};</pre>",
         it.name.as_ref().unwrap(),
-        t.generics.print(),
-        where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
-        type_ = t.type_.print()
+        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())
     );
 
     document(w, cx, it, None);
@@ -4103,25 +4104,25 @@ fn item_typedef(
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: &Cache) {
+fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
     writeln!(w, "<pre class=\"rust foreigntype\">extern {{");
     render_attributes(w, it, false);
     write!(
         w,
         "    {}type {};\n}}</pre>",
-        it.visibility.print_with_space(cx.tcx(), it.def_id),
+        it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
         it.name.as_ref().unwrap(),
     );
 
     document(w, cx, it, None);
 
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: &Cache) {
+fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
 
     if it.is_struct()
@@ -4156,7 +4157,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache:
     }
 
     if it.is_crate() {
-        if let Some(ref version) = cache.crate_version {
+        if let Some(ref version) = cx.cache.crate_version {
             write!(
                 buffer,
                 "<div class=\"block version\">\
@@ -4245,12 +4246,13 @@ fn get_methods(
     for_deref: bool,
     used_links: &mut FxHashSet<String>,
     deref_mut: bool,
+    cache: &Cache,
 ) -> Vec<String> {
     i.items
         .iter()
         .filter_map(|item| match item.name {
             Some(ref name) if !name.is_empty() && item.is_method() => {
-                if !for_deref || should_render_item(item, deref_mut) {
+                if !for_deref || should_render_item(item, deref_mut, cache) {
                     Some(format!(
                         "<a href=\"#{}\">{}</a>",
                         get_next_url(used_links, format!("method.{}", name)),
@@ -4283,8 +4285,7 @@ fn small_url_encode(s: &str) -> String {
 
 fn sidebar_assoc_items(cx: &Context<'_>, it: &clean::Item) -> String {
     let mut out = String::new();
-    let c = cache();
-    if let Some(v) = c.impls.get(&it.def_id) {
+    if let Some(v) = cx.cache.impls.get(&it.def_id) {
         let mut used_links = FxHashSet::default();
 
         {
@@ -4292,7 +4293,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, it: &clean::Item) -> String {
             let mut ret = v
                 .iter()
                 .filter(|i| i.inner_impl().trait_.is_none())
-                .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false))
+                .flat_map(move |i| {
+                    get_methods(i.inner_impl(), false, used_links_bor, false, &cx.cache)
+                })
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 // We want links' order to be reproducible so we don't use unstable sort.
@@ -4309,7 +4312,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, it: &clean::Item) -> String {
             if let Some(impl_) = v
                 .iter()
                 .filter(|i| i.inner_impl().trait_.is_some())
-                .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
+                .find(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == cx.cache.deref_trait_did)
             {
                 out.push_str(&sidebar_deref_methods(cx, impl_, v));
             }
@@ -4320,9 +4323,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, it: &clean::Item) -> String {
                     .iter()
                     .filter_map(|it| {
                         if let Some(ref i) = it.inner_impl().trait_ {
-                            let i_display = format!("{:#}", i.print());
+                            let i_display = format!("{:#}", i.print(cx.cache()));
                             let out = Escape(&i_display);
-                            let encoded = small_url_encode(&format!("{:#}", i.print()));
+                            let encoded = small_url_encode(&format!("{:#}", i.print(cx.cache())));
                             let generated = format!(
                                 "<a href=\"#impl-{}\">{}{}</a>",
                                 encoded,
@@ -4380,7 +4383,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, it: &clean::Item) -> String {
 
 fn sidebar_deref_methods(cx: &Context<'_>, impl_: &Impl, v: &Vec<Impl>) -> String {
     let mut out = String::new();
-    let c = cache();
+    let c = cx.cache();
 
     debug!("found Deref: {:?}", impl_);
     if let Some((target, real_target)) =
@@ -4396,9 +4399,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, impl_: &Impl, v: &Vec<Impl>) -> Strin
         let deref_mut = v
             .iter()
             .filter(|i| i.inner_impl().trait_.is_some())
-            .any(|i| i.inner_impl().trait_.def_id() == c.deref_mut_trait_did);
+            .any(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == c.deref_mut_trait_did);
         let inner_impl = target
-            .def_id()
+            .def_id_full(cx.cache())
             .or_else(|| {
                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
             })
@@ -4409,18 +4412,18 @@ fn sidebar_deref_methods(cx: &Context<'_>, impl_: &Impl, v: &Vec<Impl>) -> Strin
             let mut ret = impls
                 .iter()
                 .filter(|i| i.inner_impl().trait_.is_none())
-                .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut))
+                .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 let deref_id_map = cx.deref_id_map.borrow();
                 let id = deref_id_map
-                    .get(&real_target.def_id().unwrap())
+                    .get(&real_target.def_id_full(cx.cache()).unwrap())
                     .expect("Deref section without derived id");
                 out.push_str(&format!(
                     "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
                     id,
-                    Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print())),
-                    Escape(&format!("{:#}", real_target.print())),
+                    Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(c))),
+                    Escape(&format!("{:#}", real_target.print(c))),
                 ));
                 // We want links' order to be reproducible so we don't use unstable sort.
                 ret.sort();
@@ -4429,14 +4432,14 @@ fn sidebar_deref_methods(cx: &Context<'_>, impl_: &Impl, v: &Vec<Impl>) -> Strin
         }
 
         // Recurse into any further impls that might exist for `target`
-        if let Some(target_did) = target.def_id() {
+        if let Some(target_did) = target.def_id_full(cx.cache()) {
             if let Some(target_impls) = c.impls.get(&target_did) {
                 if let Some(target_deref_impl) = target_impls
                     .iter()
                     .filter(|i| i.inner_impl().trait_.is_some())
-                    .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
+                    .find(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == c.deref_trait_did)
                 {
-                    if let Some(type_did) = impl_.inner_impl().for_.def_id() {
+                    if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) {
                         // `impl Deref<Target = S> for S`
                         if target_did == type_did {
                             // Avoid infinite cycles
@@ -4473,17 +4476,21 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
     }
 }
 
-fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String {
-    small_url_encode(&format!("impl-{:#}-for-{:#}", trait_.print(), for_.print()))
+fn get_id_for_impl_on_foreign_type(
+    for_: &clean::Type,
+    trait_: &clean::Type,
+    cache: &Cache,
+) -> String {
+    small_url_encode(&format!("impl-{:#}-for-{:#}", trait_.print(cache), for_.print(cache)))
 }
 
-fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
+fn extract_for_impl_name(item: &clean::Item, cache: &Cache) -> Option<(String, String)> {
     match *item.kind {
         clean::ItemKind::ImplItem(ref i) => {
             if let Some(ref trait_) = i.trait_ {
                 Some((
-                    format!("{:#}", i.for_.print()),
-                    get_id_for_impl_on_foreign_type(&i.for_, trait_),
+                    format!("{:#}", i.for_.print(cache)),
+                    get_id_for_impl_on_foreign_type(&i.for_, trait_, cache),
                 ))
             } else {
                 None
@@ -4570,13 +4577,16 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
         ));
     }
 
-    let c = cache();
-
-    if let Some(implementors) = c.implementors.get(&it.def_id) {
+    if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
         let mut res = implementors
             .iter()
-            .filter(|i| i.inner_impl().for_.def_id().map_or(false, |d| !c.paths.contains_key(&d)))
-            .filter_map(|i| extract_for_impl_name(&i.impl_item))
+            .filter(|i| {
+                i.inner_impl()
+                    .for_
+                    .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()))
             .collect::<Vec<_>>();
 
         if !res.is_empty() {
@@ -4815,9 +4825,9 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
     document(w, cx, it, None)
 }
 
-fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: &Cache) {
+fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
     document(w, cx, it, None);
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
@@ -4836,11 +4846,10 @@ fn make_item_keywords(it: &clean::Item) -> String {
 /// types are re-exported, we don't use the corresponding
 /// entry from the js file, as inlining will have already
 /// picked up the impl
-fn collect_paths_for_type(first_ty: clean::Type) -> Vec<String> {
+fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
     let mut out = Vec::new();
     let mut visited = FxHashSet::default();
     let mut work = VecDeque::new();
-    let cache = cache();
 
     work.push_back(first_ty);
 
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 512c9124727..a8a4b74b818 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -32,6 +32,7 @@ crate struct JsonRenderer<'tcx> {
     index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
     /// The directory where the blob will be written to.
     out_path: PathBuf,
+    cache: Rc<Cache>,
 }
 
 impl JsonRenderer<'_> {
@@ -39,12 +40,8 @@ impl JsonRenderer<'_> {
         self.tcx.sess
     }
 
-    fn get_trait_implementors(
-        &mut self,
-        id: rustc_span::def_id::DefId,
-        cache: &Cache,
-    ) -> Vec<types::Id> {
-        cache
+    fn get_trait_implementors(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+        Rc::clone(&self.cache)
             .implementors
             .get(&id)
             .map(|implementors| {
@@ -52,7 +49,7 @@ impl JsonRenderer<'_> {
                     .iter()
                     .map(|i| {
                         let item = &i.impl_item;
-                        self.item(item.clone(), cache).unwrap();
+                        self.item(item.clone()).unwrap();
                         item.def_id.into()
                     })
                     .collect()
@@ -60,8 +57,8 @@ impl JsonRenderer<'_> {
             .unwrap_or_default()
     }
 
-    fn get_impls(&mut self, id: rustc_span::def_id::DefId, cache: &Cache) -> Vec<types::Id> {
-        cache
+    fn get_impls(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+        Rc::clone(&self.cache)
             .impls
             .get(&id)
             .map(|impls| {
@@ -70,7 +67,7 @@ impl JsonRenderer<'_> {
                     .filter_map(|i| {
                         let item = &i.impl_item;
                         if item.def_id.is_local() {
-                            self.item(item.clone(), cache).unwrap();
+                            self.item(item.clone()).unwrap();
                             Some(item.def_id.into())
                         } else {
                             None
@@ -81,24 +78,25 @@ impl JsonRenderer<'_> {
             .unwrap_or_default()
     }
 
-    fn get_trait_items(&mut self, cache: &Cache) -> Vec<(types::Id, types::Item)> {
-        cache
+    fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
+        Rc::clone(&self.cache)
             .traits
             .iter()
             .filter_map(|(&id, trait_item)| {
                 // only need to synthesize items for external traits
                 if !id.is_local() {
-                    trait_item.items.clone().into_iter().for_each(|i| self.item(i, cache).unwrap());
+                    trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
                     Some((
                         id.into(),
                         types::Item {
                             id: id.into(),
                             crate_id: id.krate.as_u32(),
-                            name: cache
+                            name: self
+                                .cache
                                 .paths
                                 .get(&id)
                                 .unwrap_or_else(|| {
-                                    cache
+                                    self.cache
                                         .external_paths
                                         .get(&id)
                                         .expect("Trait should either be in local or external paths")
@@ -134,7 +132,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         options: RenderOptions,
         _render_info: RenderInfo,
         _edition: Edition,
-        _cache: &mut Cache,
+        cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         debug!("Initializing json renderer");
@@ -143,6 +141,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 tcx,
                 index: Rc::new(RefCell::new(FxHashMap::default())),
                 out_path: options.output,
+                cache: Rc::new(cache),
             },
             krate,
         ))
@@ -151,18 +150,18 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     /// Inserts an item into the index. This should be used rather than directly calling insert on
     /// the hashmap because certain items (traits and types) need to have their mappings for trait
     /// implementations filled out before they're inserted.
-    fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> {
+    fn item(&mut self, item: clean::Item) -> Result<(), Error> {
         // Flatten items that recursively store other items
-        item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap());
+        item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
 
         let id = item.def_id;
         if let Some(mut new_item) = self.convert_item(item) {
             if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner {
-                t.implementors = self.get_trait_implementors(id, cache)
+                t.implementors = self.get_trait_implementors(id)
             } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner {
-                s.impls = self.get_impls(id, cache)
+                s.impls = self.get_impls(id)
             } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner {
-                e.impls = self.get_impls(id, cache)
+                e.impls = self.get_impls(id)
             }
             let removed = self.index.borrow_mut().insert(id.into(), new_item.clone());
             // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
@@ -175,27 +174,20 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         Ok(())
     }
 
-    fn mod_item_in(
-        &mut self,
-        item: &clean::Item,
-        _module_name: &str,
-        cache: &Cache,
-    ) -> Result<(), Error> {
+    fn mod_item_in(&mut self, item: &clean::Item, _module_name: &str) -> Result<(), Error> {
         use clean::types::ItemKind::*;
         if let ModuleItem(m) = &*item.kind {
             for item in &m.items {
                 match &*item.kind {
                     // These don't have names so they don't get added to the output by default
-                    ImportItem(_) => self.item(item.clone(), cache).unwrap(),
-                    ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(),
-                    ImplItem(i) => {
-                        i.items.iter().for_each(|i| self.item(i.clone(), cache).unwrap())
-                    }
+                    ImportItem(_) => self.item(item.clone()).unwrap(),
+                    ExternCrateItem(_, _) => self.item(item.clone()).unwrap(),
+                    ImplItem(i) => i.items.iter().for_each(|i| self.item(i.clone()).unwrap()),
                     _ => {}
                 }
             }
         }
-        self.item(item.clone(), cache).unwrap();
+        self.item(item.clone()).unwrap();
         Ok(())
     }
 
@@ -206,22 +198,22 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     fn after_krate(
         &mut self,
         krate: &clean::Crate,
-        cache: &Cache,
         _diag: &rustc_errors::Handler,
     ) -> Result<(), Error> {
         debug!("Done with crate");
         let mut index = (*self.index).clone().into_inner();
-        index.extend(self.get_trait_items(cache));
+        index.extend(self.get_trait_items());
         let output = types::Crate {
             root: types::Id(String::from("0:0")),
             crate_version: krate.version.clone(),
-            includes_private: cache.document_private,
+            includes_private: self.cache.document_private,
             index,
-            paths: cache
+            paths: self
+                .cache
                 .paths
                 .clone()
                 .into_iter()
-                .chain(cache.external_paths.clone().into_iter())
+                .chain(self.cache.external_paths.clone().into_iter())
                 .map(|(k, (path, kind))| {
                     (
                         k.into(),
@@ -229,7 +221,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                     )
                 })
                 .collect(),
-            external_crates: cache
+            external_crates: self
+                .cache
                 .extern_locations
                 .iter()
                 .map(|(k, v)| {
@@ -254,4 +247,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         serde_json::ser::to_writer(&file, &output).unwrap();
         Ok(())
     }
+
+    fn cache(&self) -> &Cache {
+        &self.cache
+    }
 }
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 05a3a15adac..61e14c05222 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -218,7 +218,12 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
             clean::ImplItem(ref impl_) => {
                 let filename = i.source.filename(self.ctx.sess());
                 if let Some(ref tr) = impl_.trait_ {
-                    debug!("impl {:#} for {:#} in {}", tr.print(), impl_.for_.print(), filename,);
+                    debug!(
+                        "impl {:#} for {:#} in {}",
+                        tr.print(&self.ctx.cache),
+                        impl_.for_.print(&self.ctx.cache),
+                        filename,
+                    );
 
                     // don't count trait impls, the missing-docs lint doesn't so we shouldn't
                     // either
@@ -227,7 +232,7 @@ 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(), filename);
+                    debug!("impl {:#} in {}", impl_.for_.print(&self.ctx.cache), filename);
                 }
             }
             _ => {
diff --git a/src/test/rustdoc-js-std/primitive.js b/src/test/rustdoc-js-std/primitive.js
new file mode 100644
index 00000000000..e5690383e4f
--- /dev/null
+++ b/src/test/rustdoc-js-std/primitive.js
@@ -0,0 +1,75 @@
+const QUERY = [
+    'i8',
+    'u32',
+    'str',
+    'char',
+    'unit',
+    'tuple',
+    'fn',
+];
+
+const EXPECTED = [
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'i8',
+                'href': '../std/primitive.i8.html',
+            },
+        ]
+    },
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'u32',
+                'href': '../std/primitive.u32.html',
+            },
+        ]
+    },
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'str',
+                'href': '../std/primitive.str.html',
+            },
+        ]
+    },
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'char',
+                'href': '../std/primitive.char.html',
+            },
+        ]
+    },
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'unit',
+                'href': '../std/primitive.unit.html',
+            },
+        ]
+    },
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'tuple',
+                'href': '../std/primitive.tuple.html',
+            },
+        ]
+    },
+    {
+        'others': [
+            {
+                'path': 'std',
+                'name': 'fn',
+                'href': '../std/primitive.fn.html',
+            },
+        ]
+    },
+];