@@ -3,7 +3,7 @@ use crate::clean::*;
3
3
use crate :: core:: DocContext ;
4
4
use crate :: fold:: DocFolder ;
5
5
6
- use rustc_data_structures:: fx:: FxHashSet ;
6
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
7
7
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
8
8
use rustc_middle:: ty:: DefIdTree ;
9
9
use rustc_span:: symbol:: sym;
@@ -54,39 +54,6 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
54
54
}
55
55
}
56
56
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
-
90
57
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
91
58
// doesn't work with it anyway, so pull them from the HIR map instead
92
59
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 {
123
90
}
124
91
}
125
92
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
+
126
150
if let Some ( ref mut it) = krate. module {
127
151
if let ModuleItem ( Module { ref mut items, .. } ) = * it. kind {
128
152
items. extend ( synth. impls ) ;
@@ -192,16 +216,20 @@ struct BadImplStripper {
192
216
}
193
217
194
218
impl BadImplStripper {
195
- fn keep_item ( & self , ty : & Type ) -> bool {
219
+ fn keep_impl ( & self , ty : & Type ) -> bool {
196
220
if let Generic ( _) = ty {
197
221
// keep impls made on generics
198
222
true
199
223
} else if let Some ( prim) = ty. primitive_type ( ) {
200
224
self . prims . contains ( & prim)
201
225
} else if let Some ( did) = ty. def_id ( ) {
202
- self . items . contains ( & did)
226
+ self . keep_impl_with_def_id ( & did)
203
227
} else {
204
228
false
205
229
}
206
230
}
231
+
232
+ fn keep_impl_with_def_id ( & self , did : & DefId ) -> bool {
233
+ self . items . contains ( did)
234
+ }
207
235
}
0 commit comments