1010
1111use clean:: * ;
1212
13+ use rustc:: util:: nodemap:: FxHashSet ;
14+ use rustc:: hir:: def_id:: DefId ;
15+
1316use super :: Pass ;
1417use core:: DocContext ;
1518use 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