1
1
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2
2
use rustc_errors:: struct_span_err;
3
3
use rustc_hir as hir;
4
+ use rustc_hir:: def:: DefKind ;
4
5
use rustc_hir:: def_id:: DefId ;
5
- use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
6
6
use rustc_index:: vec:: IndexVec ;
7
7
use rustc_middle:: traits:: specialization_graph:: OverlapMode ;
8
8
use rustc_middle:: ty:: { self , TyCtxt } ;
@@ -12,7 +12,10 @@ use smallvec::SmallVec;
12
12
use std:: collections:: hash_map:: Entry ;
13
13
14
14
pub fn crate_inherent_impls_overlap_check ( tcx : TyCtxt < ' _ > , ( ) : ( ) ) {
15
- tcx. hir ( ) . visit_all_item_likes ( & mut InherentOverlapChecker { tcx } ) ;
15
+ let mut inherent_overlap_checker = InherentOverlapChecker { tcx } ;
16
+ for id in tcx. hir ( ) . items ( ) {
17
+ inherent_overlap_checker. check_item ( id) ;
18
+ }
16
19
}
17
20
18
21
struct InherentOverlapChecker < ' tcx > {
@@ -121,200 +124,184 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
121
124
|| true ,
122
125
) ;
123
126
}
124
- }
125
127
126
- impl < ' tcx > ItemLikeVisitor < ' _ > for InherentOverlapChecker < ' tcx > {
127
- fn visit_item ( & mut self , item : & hir:: Item < ' _ > ) {
128
- match item. kind {
129
- hir:: ItemKind :: Enum ( ..)
130
- | hir:: ItemKind :: Struct ( ..)
131
- | hir:: ItemKind :: Trait ( ..)
132
- | hir:: ItemKind :: Union ( ..) => {
133
- let impls = self . tcx . inherent_impls ( item. def_id ) ;
128
+ fn check_item ( & mut self , id : hir:: ItemId ) {
129
+ let def_kind = self . tcx . hir ( ) . def_kind ( id. def_id ) ;
130
+ if !matches ! ( def_kind, DefKind :: Enum | DefKind :: Struct | DefKind :: Trait | DefKind :: Union ) {
131
+ return ;
132
+ }
134
133
135
- // If there is only one inherent impl block,
136
- // there is nothing to overlap check it with
137
- if impls. len ( ) <= 1 {
138
- return ;
139
- }
134
+ let impls = self . tcx . inherent_impls ( id. def_id ) ;
140
135
141
- let overlap_mode = OverlapMode :: get ( self . tcx , item. def_id . to_def_id ( ) ) ;
136
+ // If there is only one inherent impl block,
137
+ // there is nothing to overlap check it with
138
+ if impls. len ( ) <= 1 {
139
+ return ;
140
+ }
142
141
143
- let impls_items = impls
144
- . iter ( )
145
- . map ( |impl_def_id| ( impl_def_id, self . tcx . associated_items ( * impl_def_id) ) )
146
- . collect :: < SmallVec < [ _ ; 8 ] > > ( ) ;
142
+ let overlap_mode = OverlapMode :: get ( self . tcx , id. def_id . to_def_id ( ) ) ;
147
143
148
- // Perform a O(n^2) algorithm for small n,
149
- // otherwise switch to an allocating algorithm with
150
- // faster asymptotic runtime.
151
- const ALLOCATING_ALGO_THRESHOLD : usize = 500 ;
152
- if impls. len ( ) < ALLOCATING_ALGO_THRESHOLD {
153
- for ( i, & ( & impl1_def_id, impl_items1) ) in impls_items. iter ( ) . enumerate ( ) {
154
- for & ( & impl2_def_id, impl_items2) in & impls_items[ ( i + 1 ) ..] {
155
- if self . impls_have_common_items ( impl_items1, impl_items2) {
156
- self . check_for_overlapping_inherent_impls (
157
- overlap_mode,
158
- impl1_def_id,
159
- impl2_def_id,
160
- ) ;
161
- }
162
- }
144
+ let impls_items = impls
145
+ . iter ( )
146
+ . map ( |impl_def_id| ( impl_def_id, self . tcx . associated_items ( * impl_def_id) ) )
147
+ . collect :: < SmallVec < [ _ ; 8 ] > > ( ) ;
148
+
149
+ // Perform a O(n^2) algorithm for small n,
150
+ // otherwise switch to an allocating algorithm with
151
+ // faster asymptotic runtime.
152
+ const ALLOCATING_ALGO_THRESHOLD : usize = 500 ;
153
+ if impls. len ( ) < ALLOCATING_ALGO_THRESHOLD {
154
+ for ( i, & ( & impl1_def_id, impl_items1) ) in impls_items. iter ( ) . enumerate ( ) {
155
+ for & ( & impl2_def_id, impl_items2) in & impls_items[ ( i + 1 ) ..] {
156
+ if self . impls_have_common_items ( impl_items1, impl_items2) {
157
+ self . check_for_overlapping_inherent_impls (
158
+ overlap_mode,
159
+ impl1_def_id,
160
+ impl2_def_id,
161
+ ) ;
163
162
}
164
- } else {
165
- // Build a set of connected regions of impl blocks.
166
- // Two impl blocks are regarded as connected if they share
167
- // an item with the same unhygienic identifier.
168
- // After we have assembled the connected regions,
169
- // run the O(n^2) algorithm on each connected region.
170
- // This is advantageous to running the algorithm over the
171
- // entire graph when there are many connected regions.
163
+ }
164
+ }
165
+ } else {
166
+ // Build a set of connected regions of impl blocks.
167
+ // Two impl blocks are regarded as connected if they share
168
+ // an item with the same unhygienic identifier.
169
+ // After we have assembled the connected regions,
170
+ // run the O(n^2) algorithm on each connected region.
171
+ // This is advantageous to running the algorithm over the
172
+ // entire graph when there are many connected regions.
172
173
173
- rustc_index:: newtype_index! {
174
- pub struct RegionId {
175
- ENCODABLE = custom
174
+ rustc_index:: newtype_index! {
175
+ pub struct RegionId {
176
+ ENCODABLE = custom
177
+ }
178
+ }
179
+ struct ConnectedRegion {
180
+ idents : SmallVec < [ Symbol ; 8 ] > ,
181
+ impl_blocks : FxHashSet < usize > ,
182
+ }
183
+ let mut connected_regions: IndexVec < RegionId , _ > = Default :: default ( ) ;
184
+ // Reverse map from the Symbol to the connected region id.
185
+ let mut connected_region_ids = FxHashMap :: default ( ) ;
186
+
187
+ for ( i, & ( & _impl_def_id, impl_items) ) in impls_items. iter ( ) . enumerate ( ) {
188
+ if impl_items. len ( ) == 0 {
189
+ continue ;
190
+ }
191
+ // First obtain a list of existing connected region ids
192
+ let mut idents_to_add = SmallVec :: < [ Symbol ; 8 ] > :: new ( ) ;
193
+ let mut ids = impl_items
194
+ . in_definition_order ( )
195
+ . filter_map ( |item| {
196
+ let entry = connected_region_ids. entry ( item. name ) ;
197
+ if let Entry :: Occupied ( e) = & entry {
198
+ Some ( * e. get ( ) )
199
+ } else {
200
+ idents_to_add. push ( item. name ) ;
201
+ None
176
202
}
203
+ } )
204
+ . collect :: < SmallVec < [ RegionId ; 8 ] > > ( ) ;
205
+ // Sort the id list so that the algorithm is deterministic
206
+ ids. sort_unstable ( ) ;
207
+ ids. dedup ( ) ;
208
+ let ids = ids;
209
+ match & ids[ ..] {
210
+ // Create a new connected region
211
+ [ ] => {
212
+ let id_to_set = connected_regions. next_index ( ) ;
213
+ // Update the connected region ids
214
+ for ident in & idents_to_add {
215
+ connected_region_ids. insert ( * ident, id_to_set) ;
216
+ }
217
+ connected_regions. insert (
218
+ id_to_set,
219
+ ConnectedRegion {
220
+ idents : idents_to_add,
221
+ impl_blocks : std:: iter:: once ( i) . collect ( ) ,
222
+ } ,
223
+ ) ;
177
224
}
178
- struct ConnectedRegion {
179
- idents : SmallVec < [ Symbol ; 8 ] > ,
180
- impl_blocks : FxHashSet < usize > ,
225
+ // Take the only id inside the list
226
+ & [ id_to_set] => {
227
+ let region = connected_regions[ id_to_set] . as_mut ( ) . unwrap ( ) ;
228
+ region. impl_blocks . insert ( i) ;
229
+ region. idents . extend_from_slice ( & idents_to_add) ;
230
+ // Update the connected region ids
231
+ for ident in & idents_to_add {
232
+ connected_region_ids. insert ( * ident, id_to_set) ;
233
+ }
181
234
}
182
- let mut connected_regions: IndexVec < RegionId , _ > = Default :: default ( ) ;
183
- // Reverse map from the Symbol to the connected region id.
184
- let mut connected_region_ids = FxHashMap :: default ( ) ;
185
-
186
- for ( i, & ( & _impl_def_id, impl_items) ) in impls_items. iter ( ) . enumerate ( ) {
187
- if impl_items. len ( ) == 0 {
188
- continue ;
235
+ // We have multiple connected regions to merge.
236
+ // In the worst case this might add impl blocks
237
+ // one by one and can thus be O(n^2) in the size
238
+ // of the resulting final connected region, but
239
+ // this is no issue as the final step to check
240
+ // for overlaps runs in O(n^2) as well.
241
+ & [ id_to_set, ..] => {
242
+ let mut region = connected_regions. remove ( id_to_set) . unwrap ( ) ;
243
+ region. impl_blocks . insert ( i) ;
244
+ region. idents . extend_from_slice ( & idents_to_add) ;
245
+ // Update the connected region ids
246
+ for ident in & idents_to_add {
247
+ connected_region_ids. insert ( * ident, id_to_set) ;
189
248
}
190
- // First obtain a list of existing connected region ids
191
- let mut idents_to_add = SmallVec :: < [ Symbol ; 8 ] > :: new ( ) ;
192
- let mut ids = impl_items
193
- . in_definition_order ( )
194
- . filter_map ( |item| {
195
- let entry = connected_region_ids. entry ( item. name ) ;
196
- if let Entry :: Occupied ( e) = & entry {
197
- Some ( * e. get ( ) )
198
- } else {
199
- idents_to_add. push ( item. name ) ;
200
- None
201
- }
202
- } )
203
- . collect :: < SmallVec < [ RegionId ; 8 ] > > ( ) ;
204
- // Sort the id list so that the algorithm is deterministic
205
- ids. sort_unstable ( ) ;
206
- ids. dedup ( ) ;
207
- let ids = ids;
208
- match & ids[ ..] {
209
- // Create a new connected region
210
- [ ] => {
211
- let id_to_set = connected_regions. next_index ( ) ;
212
- // Update the connected region ids
213
- for ident in & idents_to_add {
214
- connected_region_ids. insert ( * ident, id_to_set) ;
215
- }
216
- connected_regions. insert (
217
- id_to_set,
218
- ConnectedRegion {
219
- idents : idents_to_add,
220
- impl_blocks : std:: iter:: once ( i) . collect ( ) ,
221
- } ,
222
- ) ;
223
- }
224
- // Take the only id inside the list
225
- & [ id_to_set] => {
226
- let region = connected_regions[ id_to_set] . as_mut ( ) . unwrap ( ) ;
227
- region. impl_blocks . insert ( i) ;
228
- region. idents . extend_from_slice ( & idents_to_add) ;
229
- // Update the connected region ids
230
- for ident in & idents_to_add {
231
- connected_region_ids. insert ( * ident, id_to_set) ;
232
- }
233
- }
234
- // We have multiple connected regions to merge.
235
- // In the worst case this might add impl blocks
236
- // one by one and can thus be O(n^2) in the size
237
- // of the resulting final connected region, but
238
- // this is no issue as the final step to check
239
- // for overlaps runs in O(n^2) as well.
240
- & [ id_to_set, ..] => {
241
- let mut region = connected_regions. remove ( id_to_set) . unwrap ( ) ;
242
- region. impl_blocks . insert ( i) ;
243
- region. idents . extend_from_slice ( & idents_to_add) ;
244
- // Update the connected region ids
245
- for ident in & idents_to_add {
246
- connected_region_ids. insert ( * ident, id_to_set) ;
247
- }
248
-
249
- // Remove other regions from ids.
250
- for & id in ids. iter ( ) {
251
- if id == id_to_set {
252
- continue ;
253
- }
254
- let r = connected_regions. remove ( id) . unwrap ( ) ;
255
- for ident in r. idents . iter ( ) {
256
- connected_region_ids. insert ( * ident, id_to_set) ;
257
- }
258
- region. idents . extend_from_slice ( & r. idents ) ;
259
- region. impl_blocks . extend ( r. impl_blocks ) ;
260
- }
261
249
262
- connected_regions. insert ( id_to_set, region) ;
250
+ // Remove other regions from ids.
251
+ for & id in ids. iter ( ) {
252
+ if id == id_to_set {
253
+ continue ;
254
+ }
255
+ let r = connected_regions. remove ( id) . unwrap ( ) ;
256
+ for ident in r. idents . iter ( ) {
257
+ connected_region_ids. insert ( * ident, id_to_set) ;
263
258
}
259
+ region. idents . extend_from_slice ( & r. idents ) ;
260
+ region. impl_blocks . extend ( r. impl_blocks ) ;
264
261
}
262
+
263
+ connected_regions. insert ( id_to_set, region) ;
265
264
}
265
+ }
266
+ }
266
267
267
- debug ! (
268
- "churning through {} components (sum={}, avg={}, var={}, max={})" ,
269
- connected_regions. len( ) ,
270
- impls. len( ) ,
271
- impls. len( ) / connected_regions. len( ) ,
272
- {
273
- let avg = impls. len( ) / connected_regions. len( ) ;
274
- let s = connected_regions
275
- . iter( )
276
- . flatten( )
277
- . map( |r| r. impl_blocks. len( ) as isize - avg as isize )
278
- . map( |v| v. abs( ) as usize )
279
- . sum:: <usize >( ) ;
280
- s / connected_regions. len( )
281
- } ,
282
- connected_regions
283
- . iter( )
284
- . flatten( )
285
- . map( |r| r. impl_blocks. len( ) )
286
- . max( )
287
- . unwrap( )
288
- ) ;
289
- // List of connected regions is built. Now, run the overlap check
290
- // for each pair of impl blocks in the same connected region.
291
- for region in connected_regions. into_iter ( ) . flatten ( ) {
292
- let mut impl_blocks =
293
- region. impl_blocks . into_iter ( ) . collect :: < SmallVec < [ usize ; 8 ] > > ( ) ;
294
- impl_blocks. sort_unstable ( ) ;
295
- for ( i, & impl1_items_idx) in impl_blocks. iter ( ) . enumerate ( ) {
296
- let & ( & impl1_def_id, impl_items1) = & impls_items[ impl1_items_idx] ;
297
- for & impl2_items_idx in impl_blocks[ ( i + 1 ) ..] . iter ( ) {
298
- let & ( & impl2_def_id, impl_items2) = & impls_items[ impl2_items_idx] ;
299
- if self . impls_have_common_items ( impl_items1, impl_items2) {
300
- self . check_for_overlapping_inherent_impls (
301
- overlap_mode,
302
- impl1_def_id,
303
- impl2_def_id,
304
- ) ;
305
- }
306
- }
268
+ debug ! (
269
+ "churning through {} components (sum={}, avg={}, var={}, max={})" ,
270
+ connected_regions. len( ) ,
271
+ impls. len( ) ,
272
+ impls. len( ) / connected_regions. len( ) ,
273
+ {
274
+ let avg = impls. len( ) / connected_regions. len( ) ;
275
+ let s = connected_regions
276
+ . iter( )
277
+ . flatten( )
278
+ . map( |r| r. impl_blocks. len( ) as isize - avg as isize )
279
+ . map( |v| v. abs( ) as usize )
280
+ . sum:: <usize >( ) ;
281
+ s / connected_regions. len( )
282
+ } ,
283
+ connected_regions. iter( ) . flatten( ) . map( |r| r. impl_blocks. len( ) ) . max( ) . unwrap( )
284
+ ) ;
285
+ // List of connected regions is built. Now, run the overlap check
286
+ // for each pair of impl blocks in the same connected region.
287
+ for region in connected_regions. into_iter ( ) . flatten ( ) {
288
+ let mut impl_blocks =
289
+ region. impl_blocks . into_iter ( ) . collect :: < SmallVec < [ usize ; 8 ] > > ( ) ;
290
+ impl_blocks. sort_unstable ( ) ;
291
+ for ( i, & impl1_items_idx) in impl_blocks. iter ( ) . enumerate ( ) {
292
+ let & ( & impl1_def_id, impl_items1) = & impls_items[ impl1_items_idx] ;
293
+ for & impl2_items_idx in impl_blocks[ ( i + 1 ) ..] . iter ( ) {
294
+ let & ( & impl2_def_id, impl_items2) = & impls_items[ impl2_items_idx] ;
295
+ if self . impls_have_common_items ( impl_items1, impl_items2) {
296
+ self . check_for_overlapping_inherent_impls (
297
+ overlap_mode,
298
+ impl1_def_id,
299
+ impl2_def_id,
300
+ ) ;
307
301
}
308
302
}
309
303
}
310
304
}
311
- _ => { }
312
305
}
313
306
}
314
-
315
- fn visit_trait_item ( & mut self , _trait_item : & hir:: TraitItem < ' _ > ) { }
316
-
317
- fn visit_impl_item ( & mut self , _impl_item : & hir:: ImplItem < ' _ > ) { }
318
-
319
- fn visit_foreign_item ( & mut self , _foreign_item : & hir:: ForeignItem < ' _ > ) { }
320
307
}
0 commit comments