Skip to content

Commit 2eb4fc8

Browse files
committed
Auto merge of #78323 - est31:smaller_list_overlap, r=varkor
Iterate over the smaller list If there are two lists of different sizes, iterating over the smaller list and then looking up in the larger list is cheaper than vice versa, because lookups scale sublinearly.
2 parents db241bb + 6c9b8ad commit 2eb4fc8

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

compiler/rustc_middle/src/ty/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ impl<'tcx> AssociatedItems<'tcx> {
266266
self.items.iter().map(|(_, v)| *v)
267267
}
268268

269+
pub fn len(&self) -> usize {
270+
self.items.len()
271+
}
272+
269273
/// Returns an iterator over all associated items with the given name, ignoring hygiene.
270274
pub fn filter_by_name_unhygienic(
271275
&self,

compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use rustc_errors::struct_span_err;
22
use rustc_hir as hir;
33
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
44
use rustc_hir::itemlikevisit::ItemLikeVisitor;
5-
use rustc_middle::ty::TyCtxt;
5+
use rustc_middle::ty::{self, TyCtxt};
66
use rustc_trait_selection::traits::{self, SkipLeakCheck};
7+
use smallvec::SmallVec;
78

89
pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) {
910
assert_eq!(crate_num, LOCAL_CRATE);
@@ -18,9 +19,18 @@ struct InherentOverlapChecker<'tcx> {
1819
impl InherentOverlapChecker<'tcx> {
1920
/// Checks whether any associated items in impls 1 and 2 share the same identifier and
2021
/// namespace.
21-
fn impls_have_common_items(&self, impl1: DefId, impl2: DefId) -> bool {
22-
let impl_items1 = self.tcx.associated_items(impl1);
23-
let impl_items2 = self.tcx.associated_items(impl2);
22+
fn impls_have_common_items(
23+
&self,
24+
impl_items1: &ty::AssociatedItems<'_>,
25+
impl_items2: &ty::AssociatedItems<'_>,
26+
) -> bool {
27+
let mut impl_items1 = &impl_items1;
28+
let mut impl_items2 = &impl_items2;
29+
30+
// Performance optimization: iterate over the smaller list
31+
if impl_items1.len() > impl_items2.len() {
32+
std::mem::swap(&mut impl_items1, &mut impl_items2);
33+
}
2434

2535
for item1 in impl_items1.in_definition_order() {
2636
let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| {
@@ -113,9 +123,20 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
113123
let ty_def_id = self.tcx.hir().local_def_id(item.hir_id);
114124
let impls = self.tcx.inherent_impls(ty_def_id);
115125

116-
for (i, &impl1_def_id) in impls.iter().enumerate() {
117-
for &impl2_def_id in &impls[(i + 1)..] {
118-
if self.impls_have_common_items(impl1_def_id, impl2_def_id) {
126+
// If there is only one inherent impl block,
127+
// there is nothing to overlap check it with
128+
if impls.len() <= 1 {
129+
return;
130+
}
131+
132+
let impls_items = impls
133+
.iter()
134+
.map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
135+
.collect::<SmallVec<[_; 8]>>();
136+
137+
for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
138+
for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
139+
if self.impls_have_common_items(impl_items1, impl_items2) {
119140
self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id);
120141
}
121142
}

0 commit comments

Comments
 (0)