diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index bb1c186668cd6..0bc10c5e10fbe 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -7,8 +7,10 @@ use std::sync::mpsc::{channel, Receiver};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
+use rustc_span::def_id::DefId;
use rustc_span::edition::Edition;
use rustc_span::source_map::FileName;
use rustc_span::{sym, Symbol};
@@ -22,13 +24,13 @@ use super::{
sidebar::{sidebar_module_like, Sidebar},
AllTypes, LinkFromSrc, StylePath,
};
-use crate::clean::{self, types::ExternalLocation, ExternalCrate};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem};
use crate::config::{ModuleSorting, RenderOptions};
use crate::docfs::{DocFS, PathError};
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
-use crate::formats::FormatRenderer;
+use crate::formats::{self, FormatRenderer};
use crate::html::escape::Escape;
use crate::html::format::{join_with_double_colon, Buffer};
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
@@ -147,6 +149,53 @@ impl SharedContext<'_> {
pub(crate) fn edition(&self) -> Edition {
self.tcx.sess.edition()
}
+
+ /// Returns a list of impls on the given type, and, if it's a type alias,
+ /// other types that it aliases.
+ pub(crate) fn all_impls_for_item<'a>(
+ &'a self,
+ it: &clean::Item,
+ did: DefId,
+ ) -> Vec<&'a formats::Impl> {
+ let tcx = self.tcx;
+ let cache = &self.cache;
+ let mut saw_impls = FxHashSet::default();
+ let mut v: Vec<&formats::Impl> = cache
+ .impls
+ .get(&did)
+ .map(Vec::as_slice)
+ .unwrap_or(&[])
+ .iter()
+ .filter(|i| saw_impls.insert(i.def_id()))
+ .collect();
+ if let TypeAliasItem(ait) = &*it.kind &&
+ let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) &&
+ let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) &&
+ let Some(av) = cache.impls.get(&aliased_type_defid) &&
+ let Some(alias_def_id) = it.item_id.as_def_id()
+ {
+ // This branch of the compiler compares types structually, but does
+ // not check trait bounds. That's probably fine, since type aliases
+ // don't normally constrain on them anyway.
+ // https://github.com/rust-lang/rust/issues/21903
+ //
+ // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification.
+ // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress.
+ let aliased_ty = tcx.type_of(alias_def_id).skip_binder();
+ let reject_cx = DeepRejectCtxt {
+ treat_obligation_params: TreatParams::AsCandidateKey,
+ };
+ v.extend(av.iter().filter(|impl_| {
+ if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() {
+ reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder())
+ && saw_impls.insert(impl_def_id)
+ } else {
+ false
+ }
+ }));
+ }
+ v
+ }
}
impl<'tcx> Context<'tcx> {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a85e8356c2f21..5adbecd6d0411 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -54,7 +54,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::TyCtxt;
use rustc_span::{
symbol::{sym, Symbol},
@@ -63,7 +62,6 @@ use rustc_span::{
use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Serialize, Serializer};
-use crate::clean::types::TypeAliasItem;
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
use crate::error::Error;
use crate::formats::cache::Cache;
@@ -1119,13 +1117,13 @@ pub(crate) fn render_all_impls(
fn render_assoc_items<'a, 'cx: 'a>(
cx: &'a mut Context<'cx>,
containing_item: &'a clean::Item,
- it: DefId,
+ did: DefId,
what: AssocItemRender<'a>,
) -> impl fmt::Display + 'a + Captures<'cx> {
let mut derefs = DefIdSet::default();
- derefs.insert(it);
+ derefs.insert(did);
display_fn(move |f| {
- render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
+ render_assoc_items_inner(f, cx, containing_item, did, what, &mut derefs);
Ok(())
})
}
@@ -1134,46 +1132,16 @@ fn render_assoc_items_inner(
mut w: &mut dyn fmt::Write,
cx: &mut Context<'_>,
containing_item: &clean::Item,
- it: DefId,
+ did: DefId,
what: AssocItemRender<'_>,
derefs: &mut DefIdSet,
) {
info!("Documenting associated items of {:?}", containing_item.name);
let shared = Rc::clone(&cx.shared);
- let cache = &shared.cache;
- let tcx = cx.tcx();
- let av = if let TypeAliasItem(ait) = &*containing_item.kind &&
- let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) &&
- let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) &&
- let Some(mut av) = cache.impls.get(&aliased_type_defid).cloned() &&
- let Some(alias_def_id) = containing_item.item_id.as_def_id()
- {
- // This branch of the compiler compares types structually, but does
- // not check trait bounds. That's probably fine, since type aliases
- // don't normally constrain on them anyway.
- // https://github.com/rust-lang/rust/issues/21903
- //
- // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification.
- // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress.
- let aliased_ty = tcx.type_of(alias_def_id).skip_binder();
- let reject_cx = DeepRejectCtxt {
- treat_obligation_params: TreatParams::AsCandidateKey,
- };
- av.retain(|impl_| {
- if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() {
- reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder())
- } else {
- false
- }
- });
- av
- } else {
- Vec::new()
- };
- let blank = Vec::new();
- let v = cache.impls.get(&it).unwrap_or(&blank);
- let (non_trait, traits): (Vec<_>, _) =
- v.iter().chain(&av[..]).partition(|i| i.inner_impl().trait_.is_none());
+ let v = shared.all_impls_for_item(containing_item, did);
+ let v = v.as_slice();
+ let (non_trait, traits): (Vec<&Impl>, _) =
+ v.iter().partition(|i| i.inner_impl().trait_.is_none());
let mut saw_impls = FxHashSet::default();
if !non_trait.is_empty() {
let mut tmp_buf = Buffer::html();
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index fce31a8423d16..6466ae825d746 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -278,11 +278,12 @@ fn sidebar_assoc_items<'a>(
links: &mut Vec>,
) {
let did = it.item_id.expect_def_id();
- let cache = cx.cache();
+ let v = cx.shared.all_impls_for_item(it, it.item_id.expect_def_id());
+ let v = v.as_slice();
let mut assoc_consts = Vec::new();
let mut methods = Vec::new();
- if let Some(v) = cache.impls.get(&did) {
+ if !v.is_empty() {
let mut used_links = FxHashSet::default();
let mut id_map = IdMap::new();
@@ -318,7 +319,7 @@ fn sidebar_assoc_items<'a>(
cx,
&mut deref_methods,
impl_,
- v,
+ v.iter().copied(),
&mut derefs,
&mut used_links,
);
@@ -348,7 +349,7 @@ fn sidebar_deref_methods<'a>(
cx: &'a Context<'_>,
out: &mut Vec>,
impl_: &Impl,
- v: &[Impl],
+ v: impl Iterator- ,
derefs: &mut DefIdSet,
used_links: &mut FxHashSet,
) {
@@ -373,7 +374,7 @@ fn sidebar_deref_methods<'a>(
// Avoid infinite cycles
return;
}
- let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
+ let deref_mut = { v }.any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
let inner_impl = target
.def_id(c)
.or_else(|| {
@@ -424,7 +425,7 @@ fn sidebar_deref_methods<'a>(
cx,
out,
target_deref_impl,
- target_impls,
+ target_impls.iter(),
derefs,
used_links,
);
diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs
index 555d0579bee79..26778c67c2433 100644
--- a/tests/rustdoc/issue-32077-type-alias-impls.rs
+++ b/tests/rustdoc/issue-32077-type-alias-impls.rs
@@ -29,6 +29,11 @@ impl Bar for GenericStruct {}
// @!has - '//h3' 'impl Bar for GenericStruct {}'
// Same goes for the `Deref` impl.
// @!has - '//h2' 'Methods from Deref'
+// @count - '//nav[@class="sidebar"]//a' 'on_alias' 1
+// @count - '//nav[@class="sidebar"]//a' 'on_gen' 1
+// @count - '//nav[@class="sidebar"]//a' 'Foo' 1
+// @!has - '//nav[@class="sidebar"]//a' 'Bar'
+// @!has - '//nav[@class="sidebar"]//a' 'on_u32'
pub type TypedefStruct = GenericStruct;
impl TypedefStruct {