Skip to content

Commit a3f98a7

Browse files
committedOct 7, 2021
Fix inherent impl overlap check.
1 parent 0157cc9 commit a3f98a7

File tree

3 files changed

+65
-45
lines changed

3 files changed

+65
-45
lines changed
 

‎compiler/rustc_index/src/vec.rs

+6
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,12 @@ impl<I: Idx, T> IndexVec<I, Option<T>> {
741741
self.ensure_contains_elem(index, || None);
742742
self[index].get_or_insert_with(value)
743743
}
744+
745+
#[inline]
746+
pub fn remove(&mut self, index: I) -> Option<T> {
747+
self.ensure_contains_elem(index, || None);
748+
self[index].take()
749+
}
744750
}
745751

746752
impl<I: Idx, T: Clone> IndexVec<I, T> {

‎compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs

+58-45
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_errors::struct_span_err;
33
use rustc_hir as hir;
44
use rustc_hir::def_id::DefId;
55
use rustc_hir::itemlikevisit::ItemLikeVisitor;
6+
use rustc_index::vec::IndexVec;
67
use rustc_middle::ty::{self, TyCtxt};
78
use rustc_span::Symbol;
89
use 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();

‎compiler/rustc_typeck/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ This API is completely unstable and subject to change.
6363
#![feature(in_band_lifetimes)]
6464
#![feature(is_sorted)]
6565
#![feature(iter_zip)]
66+
#![feature(min_specialization)]
6667
#![feature(nll)]
6768
#![feature(try_blocks)]
6869
#![feature(never_type)]

0 commit comments

Comments
 (0)
Please sign in to comment.