From 44e6f2e90fa050c490c2d79a3c65866cb5be3b34 Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Sat, 21 Aug 2021 20:58:23 -0700
Subject: [PATCH 1/8] Remove unnecessary `Cache.*_did` fields

They can be obtained by accessing the `TyCtxt` where they are needed.
---
 src/librustdoc/clean/utils.rs     |  4 ---
 src/librustdoc/formats/cache.rs   |  3 ---
 src/librustdoc/html/render/mod.rs | 41 ++++++++++++++-----------------
 3 files changed, 19 insertions(+), 29 deletions(-)

diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index de2cd60d2edc..873ecd759ebb 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -29,10 +29,6 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
     let krate = cx.tcx.hir().krate();
     let module = crate::visit_ast::RustdocVisitor::new(cx).visit(krate);
 
-    cx.cache.deref_trait_did = cx.tcx.lang_items().deref_trait();
-    cx.cache.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
-    cx.cache.owned_box_did = cx.tcx.lang_items().owned_box();
-
     let mut externs = Vec::new();
     for &cnum in cx.tcx.crates(()).iter() {
         externs.push(ExternalCrate { crate_num: cnum });
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 1830909d9446..a88f82dadda1 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -98,9 +98,6 @@ crate struct Cache {
     stripped_mod: bool,
 
     crate search_index: Vec<IndexItem>,
-    crate deref_trait_did: Option<DefId>,
-    crate deref_mut_trait_did: Option<DefId>,
-    crate owned_box_did: Option<DefId>,
 
     // In rare case where a structure is defined in one module but implemented
     // in another, if the implementing module is parsed before defining module,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 172fe5d164b7..f8f71c6f3daf 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1069,13 +1069,13 @@ fn render_assoc_items(
         return;
     }
     if !traits.is_empty() {
-        let deref_impl = traits
-            .iter()
-            .find(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did);
+        let deref_impl = traits.iter().find(|t| {
+            t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
+        });
         if let Some(impl_) = deref_impl {
-            let has_deref_mut = traits
-                .iter()
-                .any(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_mut_trait_did);
+            let has_deref_mut = traits.iter().any(|t| {
+                t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait()
+            });
             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
         }
         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
@@ -1165,7 +1165,7 @@ fn render_deref_methods(
     }
 }
 
-fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool {
+fn should_render_item(item: &clean::Item, deref_mut_: bool, cx: &Context<'_>) -> bool {
     let self_type_opt = match *item.kind {
         clean::MethodItem(ref method, _) => method.decl.self_type(),
         clean::TyMethodItem(ref method) => method.decl.self_type(),
@@ -1179,7 +1179,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo
                 (mutability == Mutability::Mut, false, false)
             }
             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
-                (false, Some(did) == cache.owned_box_did, false)
+                (false, Some(did) == cx.tcx().lang_items().owned_box(), false)
             }
             SelfTy::SelfValue => (false, false, true),
             _ => (false, false, false),
@@ -1302,7 +1302,7 @@ fn render_impl(
             && match render_mode {
                 RenderMode::Normal => true,
                 RenderMode::ForDeref { mut_: deref_mut_ } => {
-                    should_render_item(&item, deref_mut_, cx.cache())
+                    should_render_item(&item, deref_mut_, cx)
                 }
             };
 
@@ -1800,13 +1800,13 @@ fn get_methods(
     for_deref: bool,
     used_links: &mut FxHashSet<String>,
     deref_mut: bool,
-    cache: &Cache,
+    cx: &Context<'_>,
 ) -> 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, cache) {
+                if !for_deref || should_render_item(item, deref_mut, cx) {
                     Some(format!(
                         "<a href=\"#{}\">{}</a>",
                         get_next_url(used_links, format!("method.{}", name)),
@@ -1868,7 +1868,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             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, cache))
+                .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false, cx))
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 // We want links' order to be reproducible so we don't use unstable sort.
@@ -1886,11 +1886,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
         }
 
         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
-            if let Some(impl_) = v
-                .iter()
-                .filter(|i| i.inner_impl().trait_.is_some())
-                .find(|i| i.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did)
-            {
+            if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| {
+                i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
+            }) {
                 sidebar_deref_methods(cx, out, impl_, v);
             }
 
@@ -1988,10 +1986,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                 }
             }
         }
-        let deref_mut = v
-            .iter()
-            .filter(|i| i.inner_impl().trait_.is_some())
-            .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did);
+        let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| {
+            i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait()
+        });
         let inner_impl = target
             .def_id_full(c)
             .or_else(|| {
@@ -2004,7 +2001,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
             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, c))
+                .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx))
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 write!(

From df281ee57b3eb04184802da552b06d1b83a04ad3 Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Fri, 27 Aug 2021 16:49:14 -0700
Subject: [PATCH 2/8] Only take `tcx` when it's all that's needed

---
 src/librustdoc/html/render/mod.rs | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f8f71c6f3daf..2c32fe305eda 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -51,6 +51,7 @@ use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{kw, sym, Symbol};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
@@ -1165,7 +1166,7 @@ fn render_deref_methods(
     }
 }
 
-fn should_render_item(item: &clean::Item, deref_mut_: bool, cx: &Context<'_>) -> bool {
+fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
     let self_type_opt = match *item.kind {
         clean::MethodItem(ref method, _) => method.decl.self_type(),
         clean::TyMethodItem(ref method) => method.decl.self_type(),
@@ -1179,7 +1180,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cx: &Context<'_>) ->
                 (mutability == Mutability::Mut, false, false)
             }
             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
-                (false, Some(did) == cx.tcx().lang_items().owned_box(), false)
+                (false, Some(did) == tcx.lang_items().owned_box(), false)
             }
             SelfTy::SelfValue => (false, false, true),
             _ => (false, false, false),
@@ -1302,7 +1303,7 @@ fn render_impl(
             && match render_mode {
                 RenderMode::Normal => true,
                 RenderMode::ForDeref { mut_: deref_mut_ } => {
-                    should_render_item(&item, deref_mut_, cx)
+                    should_render_item(&item, deref_mut_, cx.tcx())
                 }
             };
 
@@ -1800,13 +1801,13 @@ fn get_methods(
     for_deref: bool,
     used_links: &mut FxHashSet<String>,
     deref_mut: bool,
-    cx: &Context<'_>,
+    tcx: TyCtxt<'_>,
 ) -> 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, cx) {
+                if !for_deref || should_render_item(item, deref_mut, tcx) {
                     Some(format!(
                         "<a href=\"#{}\">{}</a>",
                         get_next_url(used_links, format!("method.{}", name)),
@@ -1868,7 +1869,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             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, cx))
+                .flat_map(move |i| {
+                    get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())
+                })
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 // We want links' order to be reproducible so we don't use unstable sort.
@@ -2001,7 +2004,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
             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, cx))
+                .flat_map(|i| {
+                    get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx.tcx())
+                })
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 write!(

From 0bb1c285af51def917dd17ec1b1815cb34d4b208 Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Sun, 22 Aug 2021 18:53:00 -0700
Subject: [PATCH 3/8] rustdoc: Get symbol for `TyParam` directly

---
 src/librustdoc/clean/utils.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 873ecd759ebb..a11b9c2af8a9 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -414,7 +414,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty
             return Generic(kw::SelfUpper);
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
-            return Generic(Symbol::intern(&path.whole_name()));
+            return Generic(path.segments[0].name);
         }
         Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
         _ => false,

From 6a84d347844afc5b228a67ac8bb147f3d0e40ddb Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Tue, 24 Aug 2021 10:33:41 -0700
Subject: [PATCH 4/8] Create a valid `Res` in `external_path()`

The order of the `where` bounds on auto trait impls changed because
rustdoc currently sorts auto trait `where` bounds based on the `Debug`
output for the bound. Now that the bounds have an actual `Res`, they are
being unintentionally sorted by their `DefId` rather than their path.
So, I had to update a test for the change in ordering of the rendered
bounds.
---
 src/librustdoc/clean/mod.rs                   | 19 +++++--------------
 src/librustdoc/clean/types.rs                 |  2 +-
 src/librustdoc/clean/utils.rs                 | 10 ++++++----
 .../rustdoc/synthetic_auto/no-redundancy.rs   |  2 +-
 4 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e2ad21bba21b..fc4f22ca4f48 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -166,7 +166,7 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
         inline::record_extern_fqn(cx, trait_ref.def_id, kind);
         let path = external_path(
             cx,
-            cx.tcx.item_name(trait_ref.def_id),
+            trait_ref.def_id,
             Some(trait_ref.def_id),
             true,
             bounds.to_vec(),
@@ -1448,19 +1448,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     AdtKind::Enum => ItemType::Enum,
                 };
                 inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs);
+                let path = external_path(cx, did, None, false, vec![], substs);
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Foreign(did) => {
                 inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-                let path = external_path(
-                    cx,
-                    cx.tcx.item_name(did),
-                    None,
-                    false,
-                    vec![],
-                    InternalSubsts::empty(),
-                );
+                let path = external_path(cx, did, None, false, vec![], InternalSubsts::empty());
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Dynamic(ref obj, ref reg) => {
@@ -1484,8 +1477,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
                 for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
-                    let path =
-                        external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
+                    let path = external_path(cx, did, Some(did), false, vec![], empty);
                     inline::record_extern_fqn(cx, did, ItemType::Trait);
                     let bound = PolyTrait {
                         trait_: ResolvedPath { path, did, is_generic: false },
@@ -1502,8 +1494,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     });
                 }
 
-                let path =
-                    external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
+                let path = external_path(cx, did, Some(did), false, bindings, substs);
                 bounds.insert(
                     0,
                     PolyTrait {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5eff56a2200e..8d89fae66577 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1158,7 +1158,7 @@ impl GenericBound {
     crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = cx.tcx.intern_substs(&[]);
-        let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
+        let path = external_path(cx, did, Some(did), false, vec![], empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
         GenericBound::TraitBound(
             PolyTrait {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index a11b9c2af8a9..b6911e888676 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -141,19 +141,21 @@ fn external_generic_args(
     }
 }
 
-// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
-// from Fn<(A, B,), C> to Fn(A, B) -> C
+/// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
+/// from `Fn<(A, B,), C>` to `Fn(A, B) -> C`
 pub(super) fn external_path(
     cx: &mut DocContext<'_>,
-    name: Symbol,
+    did: DefId,
     trait_did: Option<DefId>,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
 ) -> Path {
+    let def_kind = cx.tcx.def_kind(did);
+    let name = cx.tcx.item_name(did);
     Path {
         global: false,
-        res: Res::Err,
+        res: Res::Def(def_kind, did),
         segments: vec![PathSegment {
             name,
             args: external_generic_args(cx, trait_did, has_self, bindings, substs),
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
index f727c9a47f26..16ab876e829e 100644
--- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -10,7 +10,7 @@ where
 
 // @has no_redundancy/struct.Outer.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Outer<T> where T: Copy + Send"
+// "impl<T> Send for Outer<T> where T: Send + Copy"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }

From c2207f5a48376c7e4ed12975ba1130680cd57455 Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Thu, 26 Aug 2021 17:47:29 -0700
Subject: [PATCH 5/8] Remove unused `hir_id` parameter from `resolve_type`

---
 src/librustdoc/clean/mod.rs   | 10 +++++-----
 src/librustdoc/clean/utils.rs |  4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index fc4f22ca4f48..0cd7d5a1ee54 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -906,7 +906,7 @@ impl Clean<bool> for hir::IsAuto {
 impl Clean<Type> for hir::TraitRef<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let path = self.path.clean(cx);
-        resolve_type(cx, path, self.hir_ref_id)
+        resolve_type(cx, path)
     }
 }
 
@@ -1164,7 +1164,7 @@ impl Clean<Item> for ty::AssocItem {
 
 fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
     use rustc_hir::GenericParamCount;
-    let hir::Ty { hir_id, span, ref kind } = *hir_ty;
+    let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
     let qpath = match kind {
         hir::TyKind::Path(qpath) => qpath,
         _ => unreachable!(),
@@ -1271,7 +1271,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
             }
             let path = path.clean(cx);
-            resolve_type(cx, path, hir_id)
+            resolve_type(cx, path)
         }
         hir::QPath::Resolved(Some(ref qself), ref p) => {
             // Try to normalize `<X as Y>::T` to a type
@@ -1292,7 +1292,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 name: p.segments.last().expect("segments were empty").ident.name,
                 self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
                 self_type: Box::new(qself.clean(cx)),
-                trait_: Box::new(resolve_type(cx, trait_path, hir_id)),
+                trait_: Box::new(resolve_type(cx, trait_path)),
             }
         }
         hir::QPath::TypeRelative(ref qself, ref segment) => {
@@ -1308,7 +1308,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 name: segment.ident.name,
                 self_def_id: res.opt_def_id(),
                 self_type: Box::new(qself.clean(cx)),
-                trait_: Box::new(resolve_type(cx, trait_path, hir_id)),
+                trait_: Box::new(resolve_type(cx, trait_path)),
             }
         }
         hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index b6911e888676..64d642884b41 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -407,8 +407,8 @@ crate fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
 }
 
 /// Given a type Path, resolve it to a Type using the TyCtxt
-crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Type {
-    debug!("resolve_type({:?},{:?})", path, id);
+crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
+    debug!("resolve_type({:?})", path);
 
     let is_generic = match path.res {
         Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)),

From 5321b35a5ad037369fabae99191c9e45111b21a9 Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Sat, 11 Sep 2021 15:43:44 -0700
Subject: [PATCH 6/8] Fix redundant arguments in `external_path()`

If the path is for a trait, it is always true that `trait_did ==
Some(did)`, so instead, `external_path()` now takes an `is_trait`
boolean.
---
 src/librustdoc/clean/mod.rs   | 18 +++++----------
 src/librustdoc/clean/types.rs |  2 +-
 src/librustdoc/clean/utils.rs | 41 +++++++++++++++++------------------
 3 files changed, 27 insertions(+), 34 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0cd7d5a1ee54..81792ece8a2b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -164,14 +164,8 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
             );
         }
         inline::record_extern_fqn(cx, trait_ref.def_id, kind);
-        let path = external_path(
-            cx,
-            trait_ref.def_id,
-            Some(trait_ref.def_id),
-            true,
-            bounds.to_vec(),
-            trait_ref.substs,
-        );
+        let path =
+            external_path(cx, trait_ref.def_id, true, true, bounds.to_vec(), trait_ref.substs);
 
         debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
@@ -1448,12 +1442,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     AdtKind::Enum => ItemType::Enum,
                 };
                 inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, did, None, false, vec![], substs);
+                let path = external_path(cx, did, false, false, vec![], substs);
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Foreign(did) => {
                 inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-                let path = external_path(cx, did, None, false, vec![], InternalSubsts::empty());
+                let path = external_path(cx, did, false, false, vec![], InternalSubsts::empty());
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Dynamic(ref obj, ref reg) => {
@@ -1477,7 +1471,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
                 for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
-                    let path = external_path(cx, did, Some(did), false, vec![], empty);
+                    let path = external_path(cx, did, true, false, vec![], empty);
                     inline::record_extern_fqn(cx, did, ItemType::Trait);
                     let bound = PolyTrait {
                         trait_: ResolvedPath { path, did, is_generic: false },
@@ -1494,7 +1488,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     });
                 }
 
-                let path = external_path(cx, did, Some(did), false, bindings, substs);
+                let path = external_path(cx, did, true, false, bindings, substs);
                 bounds.insert(
                     0,
                     PolyTrait {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8d89fae66577..0737ff8c6c20 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1158,7 +1158,7 @@ impl GenericBound {
     crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = cx.tcx.intern_substs(&[]);
-        let path = external_path(cx, did, Some(did), false, vec![], empty);
+        let path = external_path(cx, did, true, false, vec![], empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
         GenericBound::TraitBound(
             PolyTrait {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 64d642884b41..57ddf81d0e04 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -93,7 +93,8 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
 
 fn external_generic_args(
     cx: &mut DocContext<'_>,
-    trait_did: Option<DefId>,
+    did: DefId,
+    is_trait: bool,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
@@ -121,32 +122,30 @@ fn external_generic_args(
         })
         .collect();
 
-    match trait_did {
-        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
-        Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => {
-            assert!(ty_kind.is_some());
-            let inputs = match ty_kind {
-                Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
-                _ => return GenericArgs::AngleBracketed { args, bindings },
-            };
-            let output = None;
-            // FIXME(#20299) return type comes from a projection now
-            // match types[1].kind {
-            //     ty::Tuple(ref v) if v.is_empty() => None, // -> ()
-            //     _ => Some(types[1].clean(cx))
-            // };
-            GenericArgs::Parenthesized { inputs, output }
-        }
-        _ => GenericArgs::AngleBracketed { args, bindings },
+    if is_trait && cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
+        assert!(ty_kind.is_some());
+        let inputs = match ty_kind {
+            Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
+            _ => return GenericArgs::AngleBracketed { args, bindings },
+        };
+        let output = None;
+        // FIXME(#20299) return type comes from a projection now
+        // match types[1].kind {
+        //     ty::Tuple(ref v) if v.is_empty() => None, // -> ()
+        //     _ => Some(types[1].clean(cx))
+        // };
+        GenericArgs::Parenthesized { inputs, output }
+    } else {
+        GenericArgs::AngleBracketed { args, bindings }
     }
 }
 
-/// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
+/// `is_trait` should be set to `true` if called on a `TraitRef`, in order to sugar
 /// from `Fn<(A, B,), C>` to `Fn(A, B) -> C`
 pub(super) fn external_path(
     cx: &mut DocContext<'_>,
     did: DefId,
-    trait_did: Option<DefId>,
+    is_trait: bool,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
@@ -158,7 +157,7 @@ pub(super) fn external_path(
         res: Res::Def(def_kind, did),
         segments: vec![PathSegment {
             name,
-            args: external_generic_args(cx, trait_did, has_self, bindings, substs),
+            args: external_generic_args(cx, did, is_trait, has_self, bindings, substs),
         }],
     }
 }

From 913764dcefb0ba69fcc1dcaa667de01273270331 Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Sat, 11 Sep 2021 15:55:21 -0700
Subject: [PATCH 7/8] Remove unnecessary `is_trait` argument

It was only used for sugaring `Fn` trait bounds, and rustdoc already
checks that the `did` is for a `Fn` (or `FnMut`, `FnOnce`) lang item,
so it's not necessary to also check that the `did` belongs to a trait.
---
 src/librustdoc/clean/mod.rs   | 11 +++++------
 src/librustdoc/clean/types.rs |  2 +-
 src/librustdoc/clean/utils.rs |  8 ++------
 3 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 81792ece8a2b..84ab987062b1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -164,8 +164,7 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
             );
         }
         inline::record_extern_fqn(cx, trait_ref.def_id, kind);
-        let path =
-            external_path(cx, trait_ref.def_id, true, true, bounds.to_vec(), trait_ref.substs);
+        let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs);
 
         debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
@@ -1442,12 +1441,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     AdtKind::Enum => ItemType::Enum,
                 };
                 inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, did, false, false, vec![], substs);
+                let path = external_path(cx, did, false, vec![], substs);
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Foreign(did) => {
                 inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-                let path = external_path(cx, did, false, false, vec![], InternalSubsts::empty());
+                let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Dynamic(ref obj, ref reg) => {
@@ -1471,7 +1470,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
                 for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
-                    let path = external_path(cx, did, true, false, vec![], empty);
+                    let path = external_path(cx, did, false, vec![], empty);
                     inline::record_extern_fqn(cx, did, ItemType::Trait);
                     let bound = PolyTrait {
                         trait_: ResolvedPath { path, did, is_generic: false },
@@ -1488,7 +1487,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     });
                 }
 
-                let path = external_path(cx, did, true, false, bindings, substs);
+                let path = external_path(cx, did, false, bindings, substs);
                 bounds.insert(
                     0,
                     PolyTrait {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 0737ff8c6c20..247a6482fdce 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1158,7 +1158,7 @@ impl GenericBound {
     crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = cx.tcx.intern_substs(&[]);
-        let path = external_path(cx, did, true, false, vec![], empty);
+        let path = external_path(cx, did, false, vec![], empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
         GenericBound::TraitBound(
             PolyTrait {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 57ddf81d0e04..912274c23d6c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -94,7 +94,6 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
 fn external_generic_args(
     cx: &mut DocContext<'_>,
     did: DefId,
-    is_trait: bool,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
@@ -122,7 +121,7 @@ fn external_generic_args(
         })
         .collect();
 
-    if is_trait && cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
+    if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
         assert!(ty_kind.is_some());
         let inputs = match ty_kind {
             Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
@@ -140,12 +139,9 @@ fn external_generic_args(
     }
 }
 
-/// `is_trait` should be set to `true` if called on a `TraitRef`, in order to sugar
-/// from `Fn<(A, B,), C>` to `Fn(A, B) -> C`
 pub(super) fn external_path(
     cx: &mut DocContext<'_>,
     did: DefId,
-    is_trait: bool,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
@@ -157,7 +153,7 @@ pub(super) fn external_path(
         res: Res::Def(def_kind, did),
         segments: vec![PathSegment {
             name,
-            args: external_generic_args(cx, did, is_trait, has_self, bindings, substs),
+            args: external_generic_args(cx, did, has_self, bindings, substs),
         }],
     }
 }

From 280fc2dcce6349beb46b099da8f5fbbf463185cd Mon Sep 17 00:00:00 2001
From: Noah Lev <camelidcamel@gmail.com>
Date: Sat, 11 Sep 2021 16:01:49 -0700
Subject: [PATCH 8/8] rustdoc: Cleanup a pattern match in
 `external_generic_args()`

---
 src/librustdoc/clean/utils.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 912274c23d6c..b0021d1234cd 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -122,9 +122,8 @@ fn external_generic_args(
         .collect();
 
     if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
-        assert!(ty_kind.is_some());
-        let inputs = match ty_kind {
-            Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
+        let inputs = match ty_kind.unwrap() {
+            ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
             _ => return GenericArgs::AngleBracketed { args, bindings },
         };
         let output = None;