Skip to content

Commit 755c02d

Browse files
filter collected trait impls against items in the crate
1 parent 354507e commit 755c02d

File tree

1 file changed

+149
-60
lines changed

1 file changed

+149
-60
lines changed

src/librustdoc/passes/collect_trait_impls.rs

+149-60
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
use clean::*;
1212

13+
use rustc::util::nodemap::FxHashSet;
14+
use rustc::hir::def_id::DefId;
15+
1316
use super::Pass;
1417
use core::DocContext;
1518
use fold::DocFolder;
@@ -22,71 +25,118 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate {
2225
let mut synth = SyntheticImplCollector::new(cx);
2326
let mut krate = synth.fold_crate(krate);
2427

25-
if let Some(ref mut it) = krate.module {
26-
if let ModuleItem(Module { ref mut items, .. }) = it.inner {
27-
items.extend(synth.impls);
28+
let prims: FxHashSet<PrimitiveType> =
29+
krate.primitives.iter().map(|p| p.1).collect();
2830

29-
for &cnum in cx.tcx.crates().iter() {
30-
for &did in cx.tcx.all_trait_implementations(cnum).iter() {
31-
inline::build_impl(cx, did, items);
32-
}
33-
}
31+
let crate_items = {
32+
let mut coll = ItemCollector::new();
33+
krate = coll.fold_crate(krate);
34+
coll.items
35+
};
3436

35-
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
36-
// doesn't work with it anyway, so pull them from the HIR map instead
37-
for &trait_did in cx.all_traits.iter() {
38-
for &impl_node in cx.tcx.hir.trait_impls(trait_did) {
39-
let impl_did = cx.tcx.hir.local_def_id(impl_node);
40-
inline::build_impl(cx, impl_did, items);
41-
}
42-
}
37+
let mut new_items = Vec::new();
38+
39+
for &cnum in cx.tcx.crates().iter() {
40+
for &did in cx.tcx.all_trait_implementations(cnum).iter() {
41+
inline::build_impl(cx, did, &mut new_items);
42+
}
43+
}
4344

44-
// Also try to inline primitive impls from other crates.
45-
let lang_items = cx.tcx.lang_items();
46-
let primitive_impls = [
47-
lang_items.isize_impl(),
48-
lang_items.i8_impl(),
49-
lang_items.i16_impl(),
50-
lang_items.i32_impl(),
51-
lang_items.i64_impl(),
52-
lang_items.i128_impl(),
53-
lang_items.usize_impl(),
54-
lang_items.u8_impl(),
55-
lang_items.u16_impl(),
56-
lang_items.u32_impl(),
57-
lang_items.u64_impl(),
58-
lang_items.u128_impl(),
59-
lang_items.f32_impl(),
60-
lang_items.f64_impl(),
61-
lang_items.f32_runtime_impl(),
62-
lang_items.f64_runtime_impl(),
63-
lang_items.char_impl(),
64-
lang_items.str_impl(),
65-
lang_items.slice_impl(),
66-
lang_items.slice_u8_impl(),
67-
lang_items.str_alloc_impl(),
68-
lang_items.slice_alloc_impl(),
69-
lang_items.slice_u8_alloc_impl(),
70-
lang_items.const_ptr_impl(),
71-
lang_items.mut_ptr_impl(),
72-
];
73-
74-
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
75-
if !def_id.is_local() {
76-
inline::build_impl(cx, def_id, items);
77-
78-
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
79-
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
80-
let mut renderinfo = cx.renderinfo.borrow_mut();
81-
82-
let new_impls: Vec<Item> = auto_impls.into_iter()
83-
.chain(blanket_impls.into_iter())
84-
.filter(|i| renderinfo.inlined.insert(i.def_id))
85-
.collect();
86-
87-
items.extend(new_impls);
45+
// Also try to inline primitive impls from other crates.
46+
let lang_items = cx.tcx.lang_items();
47+
let primitive_impls = [
48+
lang_items.isize_impl(),
49+
lang_items.i8_impl(),
50+
lang_items.i16_impl(),
51+
lang_items.i32_impl(),
52+
lang_items.i64_impl(),
53+
lang_items.i128_impl(),
54+
lang_items.usize_impl(),
55+
lang_items.u8_impl(),
56+
lang_items.u16_impl(),
57+
lang_items.u32_impl(),
58+
lang_items.u64_impl(),
59+
lang_items.u128_impl(),
60+
lang_items.f32_impl(),
61+
lang_items.f64_impl(),
62+
lang_items.f32_runtime_impl(),
63+
lang_items.f64_runtime_impl(),
64+
lang_items.char_impl(),
65+
lang_items.str_impl(),
66+
lang_items.slice_impl(),
67+
lang_items.slice_u8_impl(),
68+
lang_items.str_alloc_impl(),
69+
lang_items.slice_alloc_impl(),
70+
lang_items.slice_u8_alloc_impl(),
71+
lang_items.const_ptr_impl(),
72+
lang_items.mut_ptr_impl(),
73+
];
74+
75+
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
76+
if !def_id.is_local() {
77+
inline::build_impl(cx, def_id, &mut new_items);
78+
79+
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
80+
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
81+
let mut renderinfo = cx.renderinfo.borrow_mut();
82+
83+
let new_impls: Vec<Item> = auto_impls.into_iter()
84+
.chain(blanket_impls.into_iter())
85+
.filter(|i| renderinfo.inlined.insert(i.def_id))
86+
.collect();
87+
88+
new_items.extend(new_impls);
89+
}
90+
}
91+
92+
let mut cleaner = BadImplStripper {
93+
prims,
94+
items: crate_items,
95+
};
96+
97+
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
98+
for it in &new_items {
99+
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner {
100+
if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
101+
let target = items.iter().filter_map(|item| {
102+
match item.inner {
103+
TypedefItem(ref t, true) => Some(&t.type_),
104+
_ => None,
105+
}
106+
}).next().expect("Deref impl without Target type");
107+
108+
if let Some(prim) = target.primitive_type() {
109+
cleaner.prims.insert(prim);
110+
} else if let Some(did) = target.def_id() {
111+
cleaner.items.insert(did);
88112
}
89113
}
114+
}
115+
}
116+
117+
new_items.retain(|it| {
118+
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner {
119+
cleaner.keep_item(for_) ||
120+
trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) ||
121+
blanket_impl.is_some()
122+
} else {
123+
true
124+
}
125+
});
126+
127+
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
128+
// doesn't work with it anyway, so pull them from the HIR map instead
129+
for &trait_did in cx.all_traits.iter() {
130+
for &impl_node in cx.tcx.hir.trait_impls(trait_did) {
131+
let impl_did = cx.tcx.hir.local_def_id(impl_node);
132+
inline::build_impl(cx, impl_did, &mut new_items);
133+
}
134+
}
135+
136+
if let Some(ref mut it) = krate.module {
137+
if let ModuleItem(Module { ref mut items, .. }) = it.inner {
138+
items.extend(synth.impls);
139+
items.extend(new_items);
90140
} else {
91141
panic!("collect-trait-impls can't run");
92142
}
@@ -128,3 +178,42 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rc
128178
self.fold_item_recur(i)
129179
}
130180
}
181+
182+
#[derive(Default)]
183+
struct ItemCollector {
184+
items: FxHashSet<DefId>,
185+
}
186+
187+
impl ItemCollector {
188+
fn new() -> Self {
189+
Self::default()
190+
}
191+
}
192+
193+
impl DocFolder for ItemCollector {
194+
fn fold_item(&mut self, i: Item) -> Option<Item> {
195+
self.items.insert(i.def_id);
196+
197+
self.fold_item_recur(i)
198+
}
199+
}
200+
201+
struct BadImplStripper {
202+
prims: FxHashSet<PrimitiveType>,
203+
items: FxHashSet<DefId>,
204+
}
205+
206+
impl BadImplStripper {
207+
fn keep_item(&self, ty: &Type) -> bool {
208+
if let Generic(_) = ty {
209+
// keep impls made on generics
210+
true
211+
} else if let Some(prim) = ty.primitive_type() {
212+
self.prims.contains(&prim)
213+
} else if let Some(did) = ty.def_id() {
214+
self.items.contains(&did)
215+
} else {
216+
false
217+
}
218+
}
219+
}

0 commit comments

Comments
 (0)