@@ -3,6 +3,7 @@ use rustc_errors::struct_span_err;
33use rustc_hir as hir;
44use rustc_hir:: def_id:: DefId ;
55use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
6+ use rustc_index:: vec:: IndexVec ;
67use rustc_middle:: ty:: { self , TyCtxt } ;
78use rustc_span:: Symbol ;
89use rustc_trait_selection:: traits:: { self , SkipLeakCheck } ;
@@ -158,22 +159,26 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
158159 // This is advantageous to running the algorithm over the
159160 // entire graph when there are many connected regions.
160161
162+ rustc_index:: newtype_index! {
163+ pub struct RegionId {
164+ ENCODABLE = custom
165+ }
166+ }
161167 struct ConnectedRegion {
162168 idents : SmallVec < [ Symbol ; 8 ] > ,
163169 impl_blocks : FxHashSet < usize > ,
164170 }
165- // Highest connected region id
166- let mut highest_region_id = 0 ;
171+ let mut connected_regions : IndexVec < RegionId , _ > = Default :: default ( ) ;
172+ // Reverse map from the Symbol to the connected region id.
167173 let mut connected_region_ids = FxHashMap :: default ( ) ;
168- let mut connected_regions = FxHashMap :: default ( ) ;
169174
170175 for ( i, & ( & _impl_def_id, impl_items) ) in impls_items. iter ( ) . enumerate ( ) {
171176 if impl_items. len ( ) == 0 {
172177 continue ;
173178 }
174179 // First obtain a list of existing connected region ids
175180 let mut idents_to_add = SmallVec :: < [ Symbol ; 8 ] > :: new ( ) ;
176- let ids = impl_items
181+ let mut ids = impl_items
177182 . in_definition_order ( )
178183 . filter_map ( |item| {
179184 let entry = connected_region_ids. entry ( item. ident . name ) ;
@@ -184,62 +189,64 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
184189 None
185190 }
186191 } )
187- . collect :: < FxHashSet < usize > > ( ) ;
188- match ids. len ( ) {
189- 0 | 1 => {
190- let id_to_set = if ids. is_empty ( ) {
191- // Create a new connected region
192- let region = ConnectedRegion {
192+ . collect :: < SmallVec < [ RegionId ; 8 ] > > ( ) ;
193+ // Sort the id list so that the algorithm is deterministic
194+ ids. sort_unstable ( ) ;
195+ let ids = ids;
196+ match & ids[ ..] {
197+ // Create a new connected region
198+ [ ] => {
199+ let id_to_set = connected_regions. next_index ( ) ;
200+ // Update the connected region ids
201+ for ident in & idents_to_add {
202+ connected_region_ids. insert ( * ident, id_to_set) ;
203+ }
204+ connected_regions. insert (
205+ id_to_set,
206+ ConnectedRegion {
193207 idents : idents_to_add,
194208 impl_blocks : std:: iter:: once ( i) . collect ( ) ,
195- } ;
196- connected_regions. insert ( highest_region_id, region) ;
197- ( highest_region_id, highest_region_id += 1 ) . 0
198- } else {
199- // Take the only id inside the list
200- let id_to_set = * ids. iter ( ) . next ( ) . unwrap ( ) ;
201- let region = connected_regions. get_mut ( & id_to_set) . unwrap ( ) ;
202- region. impl_blocks . insert ( i) ;
203- region. idents . extend_from_slice ( & idents_to_add) ;
204- id_to_set
205- } ;
206- let ( _id, region) = connected_regions. iter ( ) . next ( ) . unwrap ( ) ;
209+ } ,
210+ ) ;
211+ }
212+ // Take the only id inside the list
213+ & [ id_to_set] => {
214+ let region = connected_regions[ id_to_set] . as_mut ( ) . unwrap ( ) ;
215+ region. impl_blocks . insert ( i) ;
216+ region. idents . extend_from_slice ( & idents_to_add) ;
207217 // Update the connected region ids
208- for ident in region . idents . iter ( ) {
218+ for ident in & idents_to_add {
209219 connected_region_ids. insert ( * ident, id_to_set) ;
210220 }
211221 }
212- _ => {
213- // We have multiple connected regions to merge.
214- // In the worst case this might add impl blocks
215- // one by one and can thus be O(n^2) in the size
216- // of the resulting final connected region, but
217- // this is no issue as the final step to check
218- // for overlaps runs in O(n^2) as well.
219-
220- // Take the smallest id from the list
221- let id_to_set = * ids. iter ( ) . min ( ) . unwrap ( ) ;
222-
223- // Sort the id list so that the algorithm is deterministic
224- let mut ids = ids. into_iter ( ) . collect :: < SmallVec < [ usize ; 8 ] > > ( ) ;
225- ids. sort_unstable ( ) ;
226-
227- let mut region = connected_regions. remove ( & id_to_set) . unwrap ( ) ;
228- region. idents . extend_from_slice ( & idents_to_add) ;
222+ // We have multiple connected regions to merge.
223+ // In the worst case this might add impl blocks
224+ // one by one and can thus be O(n^2) in the size
225+ // of the resulting final connected region, but
226+ // this is no issue as the final step to check
227+ // for overlaps runs in O(n^2) as well.
228+ & [ id_to_set, ..] => {
229+ let mut region = connected_regions. remove ( id_to_set) . unwrap ( ) ;
229230 region. impl_blocks . insert ( i) ;
231+ region. idents . extend_from_slice ( & idents_to_add) ;
232+ // Update the connected region ids
233+ for ident in & idents_to_add {
234+ connected_region_ids. insert ( * ident, id_to_set) ;
235+ }
230236
237+ // Remove other regions from ids.
231238 for & id in ids. iter ( ) {
232239 if id == id_to_set {
233240 continue ;
234241 }
235- let r = connected_regions. remove ( & id) . unwrap ( ) ;
236- // Update the connected region ids
242+ let r = connected_regions. remove ( id) . unwrap ( ) ;
237243 for ident in r. idents . iter ( ) {
238244 connected_region_ids. insert ( * ident, id_to_set) ;
239245 }
240246 region. idents . extend_from_slice ( & r. idents ) ;
241247 region. impl_blocks . extend ( r. impl_blocks ) ;
242248 }
249+
243250 connected_regions. insert ( id_to_set, region) ;
244251 }
245252 }
@@ -254,16 +261,22 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
254261 let avg = impls. len( ) / connected_regions. len( ) ;
255262 let s = connected_regions
256263 . iter( )
257- . map( |r| r. 1 . impl_blocks. len( ) as isize - avg as isize )
264+ . flatten( )
265+ . map( |r| r. impl_blocks. len( ) as isize - avg as isize )
258266 . map( |v| v. abs( ) as usize )
259267 . sum:: <usize >( ) ;
260268 s / connected_regions. len( )
261269 } ,
262- connected_regions. iter( ) . map( |r| r. 1 . impl_blocks. len( ) ) . max( ) . unwrap( )
270+ connected_regions
271+ . iter( )
272+ . flatten( )
273+ . map( |r| r. impl_blocks. len( ) )
274+ . max( )
275+ . unwrap( )
263276 ) ;
264277 // List of connected regions is built. Now, run the overlap check
265278 // for each pair of impl blocks in the same connected region.
266- for ( _id , region) in connected_regions. into_iter ( ) {
279+ for region in connected_regions. into_iter ( ) . flatten ( ) {
267280 let mut impl_blocks =
268281 region. impl_blocks . into_iter ( ) . collect :: < SmallVec < [ usize ; 8 ] > > ( ) ;
269282 impl_blocks. sort_unstable ( ) ;
0 commit comments