@@ -3,6 +3,7 @@ use rustc_errors::struct_span_err;
3
3
use rustc_hir as hir;
4
4
use rustc_hir:: def_id:: DefId ;
5
5
use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
6
+ use rustc_index:: vec:: IndexVec ;
6
7
use rustc_middle:: ty:: { self , TyCtxt } ;
7
8
use rustc_span:: Symbol ;
8
9
use rustc_trait_selection:: traits:: { self , SkipLeakCheck } ;
@@ -158,22 +159,26 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
158
159
// This is advantageous to running the algorithm over the
159
160
// entire graph when there are many connected regions.
160
161
162
+ rustc_index:: newtype_index! {
163
+ pub struct RegionId {
164
+ ENCODABLE = custom
165
+ }
166
+ }
161
167
struct ConnectedRegion {
162
168
idents : SmallVec < [ Symbol ; 8 ] > ,
163
169
impl_blocks : FxHashSet < usize > ,
164
170
}
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.
167
173
let mut connected_region_ids = FxHashMap :: default ( ) ;
168
- let mut connected_regions = FxHashMap :: default ( ) ;
169
174
170
175
for ( i, & ( & _impl_def_id, impl_items) ) in impls_items. iter ( ) . enumerate ( ) {
171
176
if impl_items. len ( ) == 0 {
172
177
continue ;
173
178
}
174
179
// First obtain a list of existing connected region ids
175
180
let mut idents_to_add = SmallVec :: < [ Symbol ; 8 ] > :: new ( ) ;
176
- let ids = impl_items
181
+ let mut ids = impl_items
177
182
. in_definition_order ( )
178
183
. filter_map ( |item| {
179
184
let entry = connected_region_ids. entry ( item. ident . name ) ;
@@ -184,62 +189,64 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
184
189
None
185
190
}
186
191
} )
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 {
193
207
idents : idents_to_add,
194
208
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) ;
207
217
// Update the connected region ids
208
- for ident in region . idents . iter ( ) {
218
+ for ident in & idents_to_add {
209
219
connected_region_ids. insert ( * ident, id_to_set) ;
210
220
}
211
221
}
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 ( ) ;
229
230
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
+ }
230
236
237
+ // Remove other regions from ids.
231
238
for & id in ids. iter ( ) {
232
239
if id == id_to_set {
233
240
continue ;
234
241
}
235
- let r = connected_regions. remove ( & id) . unwrap ( ) ;
236
- // Update the connected region ids
242
+ let r = connected_regions. remove ( id) . unwrap ( ) ;
237
243
for ident in r. idents . iter ( ) {
238
244
connected_region_ids. insert ( * ident, id_to_set) ;
239
245
}
240
246
region. idents . extend_from_slice ( & r. idents ) ;
241
247
region. impl_blocks . extend ( r. impl_blocks ) ;
242
248
}
249
+
243
250
connected_regions. insert ( id_to_set, region) ;
244
251
}
245
252
}
@@ -254,16 +261,22 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
254
261
let avg = impls. len( ) / connected_regions. len( ) ;
255
262
let s = connected_regions
256
263
. 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 )
258
266
. map( |v| v. abs( ) as usize )
259
267
. sum:: <usize >( ) ;
260
268
s / connected_regions. len( )
261
269
} ,
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( )
263
276
) ;
264
277
// List of connected regions is built. Now, run the overlap check
265
278
// 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 ( ) {
267
280
let mut impl_blocks =
268
281
region. impl_blocks . into_iter ( ) . collect :: < SmallVec < [ usize ; 8 ] > > ( ) ;
269
282
impl_blocks. sort_unstable ( ) ;
0 commit comments