11use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
22use rustc_errors:: struct_span_err;
33use rustc_hir as hir;
4+ use rustc_hir:: def:: DefKind ;
45use rustc_hir:: def_id:: DefId ;
5- use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
66use rustc_index:: vec:: IndexVec ;
77use rustc_middle:: traits:: specialization_graph:: OverlapMode ;
88use rustc_middle:: ty:: { self , TyCtxt } ;
@@ -12,7 +12,10 @@ use smallvec::SmallVec;
1212use std:: collections:: hash_map:: Entry ;
1313
1414pub 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+ }
1619}
1720
1821struct InherentOverlapChecker < ' tcx > {
@@ -121,200 +124,184 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
121124 || true ,
122125 ) ;
123126 }
124- }
125127
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+ }
134133
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 ) ;
140135
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+ }
142141
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 ( ) ) ;
147143
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+ ) ;
163162 }
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.
172173
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
176202 }
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+ ) ;
177224 }
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+ }
181234 }
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) ;
189248 }
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- }
261249
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) ;
263258 }
259+ region. idents . extend_from_slice ( & r. idents ) ;
260+ region. impl_blocks . extend ( r. impl_blocks ) ;
264261 }
262+
263+ connected_regions. insert ( id_to_set, region) ;
265264 }
265+ }
266+ }
266267
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+ ) ;
307301 }
308302 }
309303 }
310304 }
311- _ => { }
312305 }
313306 }
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 < ' _ > ) { }
320307}
0 commit comments