Skip to content

Commit ad4e98e

Browse files
committed
Auto merge of #96091 - GuillaumeGomez:duplicated-blanket-impls, r=notriddle
Fix rustdoc duplicated blanket impls Fixes #96036. I think it'll not be great performance-wise but I couldn't find another way to prevent that unfortunately... r? `@notriddle`
2 parents 1ec2c13 + 6d10fd0 commit ad4e98e

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

src/librustdoc/formats/cache.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ crate struct Cache {
127127
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
128128
struct CacheBuilder<'a, 'tcx> {
129129
cache: &'a mut Cache,
130+
/// This field is used to prevent duplicated impl blocks.
131+
impl_ids: FxHashMap<DefId, FxHashSet<DefId>>,
130132
tcx: TyCtxt<'tcx>,
131133
}
132134

@@ -170,12 +172,19 @@ impl Cache {
170172
.insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive));
171173
}
172174

173-
krate = CacheBuilder { tcx, cache: &mut cx.cache }.fold_crate(krate);
175+
let (krate, mut impl_ids) = {
176+
let mut cache_builder =
177+
CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: FxHashMap::default() };
178+
krate = cache_builder.fold_crate(krate);
179+
(krate, cache_builder.impl_ids)
180+
};
174181

175182
for (trait_did, dids, impl_) in cx.cache.orphan_trait_impls.drain(..) {
176183
if cx.cache.traits.contains_key(&trait_did) {
177184
for did in dids {
178-
cx.cache.impls.entry(did).or_default().push(impl_.clone());
185+
if impl_ids.entry(did).or_default().insert(impl_.def_id()) {
186+
cx.cache.impls.entry(did).or_default().push(impl_.clone());
187+
}
179188
}
180189
}
181190
}
@@ -467,7 +476,13 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
467476
let impl_item = Impl { impl_item: item };
468477
if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
469478
for did in dids {
470-
self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
479+
if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
480+
self.cache
481+
.impls
482+
.entry(did)
483+
.or_insert_with(Vec::new)
484+
.push(impl_item.clone());
485+
}
471486
}
472487
} else {
473488
let trait_did = impl_item.trait_did().expect("no trait did");

src/librustdoc/formats/mod.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
66

77
crate use renderer::{run_format, FormatRenderer};
88

9-
use crate::clean;
9+
use crate::clean::{self, ItemId};
1010

1111
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
1212
/// impl.
@@ -40,4 +40,24 @@ impl Impl {
4040
crate fn trait_did(&self) -> Option<DefId> {
4141
self.inner_impl().trait_.as_ref().map(|t| t.def_id())
4242
}
43+
44+
/// This function is used to extract a `DefId` to be used as a key for the `Cache::impls` field.
45+
///
46+
/// It allows to prevent having duplicated implementations showing up (the biggest issue was
47+
/// with blanket impls).
48+
///
49+
/// It panics if `self` is a `ItemId::Primitive`.
50+
crate fn def_id(&self) -> DefId {
51+
match self.impl_item.item_id {
52+
ItemId::Blanket { impl_id, .. } => impl_id,
53+
ItemId::Auto { trait_, .. } => trait_,
54+
ItemId::DefId(def_id) => def_id,
55+
ItemId::Primitive(_, _) => {
56+
panic!(
57+
"Unexpected ItemId::Primitive in expect_def_id: {:?}",
58+
self.impl_item.item_id
59+
)
60+
}
61+
}
62+
}
4363
}

src/test/rustdoc/duplicated_impl.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// This test ensures that the same implementation doesn't show more than once.
2+
// It's a regression test for https://github.com/rust-lang/rust/issues/96036.
3+
4+
#![crate_name = "foo"]
5+
6+
// We check that there is only one "impl<T> Something<Whatever> for T" listed in the
7+
// blanket implementations.
8+
9+
// @has 'foo/struct.Whatever.html'
10+
// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
11+
12+
pub trait Something<T> { }
13+
pub struct Whatever;
14+
impl<T> Something<Whatever> for T {}

0 commit comments

Comments
 (0)