@@ -3,7 +3,7 @@ use crate::clean::*;
33use crate :: core:: DocContext ;
44use crate :: fold:: DocFolder ;
55
6- use rustc_data_structures:: fx:: FxHashSet ;
6+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
77use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
88use rustc_middle:: ty:: DefIdTree ;
99use rustc_span:: symbol:: sym;
@@ -54,39 +54,6 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
5454 }
5555 }
5656
57- let mut cleaner = BadImplStripper { prims, items : crate_items } ;
58-
59- // scan through included items ahead of time to splice in Deref targets to the "valid" sets
60- for it in & new_items {
61- if let ImplItem ( Impl { ref for_, ref trait_, ref items, .. } ) = * it. kind {
62- if cleaner. keep_item ( for_) && trait_. def_id ( ) == cx. tcx . lang_items ( ) . deref_trait ( ) {
63- let target = items
64- . iter ( )
65- . find_map ( |item| match * item. kind {
66- TypedefItem ( ref t, true ) => Some ( & t. type_ ) ,
67- _ => None ,
68- } )
69- . expect ( "Deref impl without Target type" ) ;
70-
71- if let Some ( prim) = target. primitive_type ( ) {
72- cleaner. prims . insert ( prim) ;
73- } else if let Some ( did) = target. def_id ( ) {
74- cleaner. items . insert ( did) ;
75- }
76- }
77- }
78- }
79-
80- new_items. retain ( |it| {
81- if let ImplItem ( Impl { ref for_, ref trait_, ref blanket_impl, .. } ) = * it. kind {
82- cleaner. keep_item ( for_)
83- || trait_. as_ref ( ) . map_or ( false , |t| cleaner. keep_item ( t) )
84- || blanket_impl. is_some ( )
85- } else {
86- true
87- }
88- } ) ;
89-
9057 // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
9158 // doesn't work with it anyway, so pull them from the HIR map instead
9259 for & trait_did in cx. tcx . all_traits ( LOCAL_CRATE ) . iter ( ) {
@@ -123,6 +90,63 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
12390 }
12491 }
12592
93+ let mut cleaner = BadImplStripper { prims, items : crate_items } ;
94+
95+ let mut type_did_to_deref_target: FxHashMap < DefId , & Type > = FxHashMap :: default ( ) ;
96+ // Gather all type to `Deref` target edges.
97+ for it in & new_items {
98+ if let ImplItem ( Impl { ref for_, ref trait_, ref items, .. } ) = * it. kind {
99+ if trait_. def_id ( ) == cx. tcx . lang_items ( ) . deref_trait ( ) {
100+ let target = items. iter ( ) . find_map ( |item| match * item. kind {
101+ TypedefItem ( ref t, true ) => Some ( & t. type_ ) ,
102+ _ => None ,
103+ } ) ;
104+ if let ( Some ( for_did) , Some ( target) ) = ( for_. def_id ( ) , target) {
105+ type_did_to_deref_target. insert ( for_did, target) ;
106+ }
107+ }
108+ }
109+ }
110+ // Follow all `Deref` targets of included items and recursively add them as valid
111+ fn add_deref_target (
112+ map : & FxHashMap < DefId , & Type > ,
113+ cleaner : & mut BadImplStripper ,
114+ type_did : & DefId ,
115+ ) {
116+ if let Some ( target) = map. get ( type_did) {
117+ debug ! ( "add_deref_target: type {:?}, target {:?}" , type_did, target) ;
118+ if let Some ( target_prim) = target. primitive_type ( ) {
119+ cleaner. prims . insert ( target_prim) ;
120+ } else if let Some ( target_did) = target. def_id ( ) {
121+ // `impl Deref<Target = S> for S`
122+ if target_did == * type_did {
123+ // Avoid infinite cycles
124+ return ;
125+ }
126+ cleaner. items . insert ( target_did) ;
127+ add_deref_target ( map, cleaner, & target_did) ;
128+ }
129+ }
130+ }
131+ for type_did in type_did_to_deref_target. keys ( ) {
132+ // Since only the `DefId` portion of the `Type` instances is known to be same for both the
133+ // `Deref` target type and the impl for type positions, this map of types is keyed by
134+ // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
135+ if cleaner. keep_impl_with_def_id ( type_did) {
136+ add_deref_target ( & type_did_to_deref_target, & mut cleaner, type_did) ;
137+ }
138+ }
139+
140+ new_items. retain ( |it| {
141+ if let ImplItem ( Impl { ref for_, ref trait_, ref blanket_impl, .. } ) = * it. kind {
142+ cleaner. keep_impl ( for_)
143+ || trait_. as_ref ( ) . map_or ( false , |t| cleaner. keep_impl ( t) )
144+ || blanket_impl. is_some ( )
145+ } else {
146+ true
147+ }
148+ } ) ;
149+
126150 if let Some ( ref mut it) = krate. module {
127151 if let ModuleItem ( Module { ref mut items, .. } ) = * it. kind {
128152 items. extend ( synth. impls ) ;
@@ -192,16 +216,20 @@ struct BadImplStripper {
192216}
193217
194218impl BadImplStripper {
195- fn keep_item ( & self , ty : & Type ) -> bool {
219+ fn keep_impl ( & self , ty : & Type ) -> bool {
196220 if let Generic ( _) = ty {
197221 // keep impls made on generics
198222 true
199223 } else if let Some ( prim) = ty. primitive_type ( ) {
200224 self . prims . contains ( & prim)
201225 } else if let Some ( did) = ty. def_id ( ) {
202- self . items . contains ( & did)
226+ self . keep_impl_with_def_id ( & did)
203227 } else {
204228 false
205229 }
206230 }
231+
232+ fn keep_impl_with_def_id ( & self , did : & DefId ) -> bool {
233+ self . items . contains ( did)
234+ }
207235}
0 commit comments