Skip to content

Commit 6c9b8ad

Browse files
committed
Precompute the associated items
The associated_items(def_id) call allocates internally. Previously, we'd have called it for each pair, so we'd have had O(n^2) many calls. By precomputing the associated items, we avoid repeating so many allocations. The only instance where this precomputation would be a regression is if there's only one inherent impl block for the type, as the inner loop then doesn't run. In that instance, we just early return. Also, use SmallVec to avoid doing an allocation at all if the number is small (the case for most impl blocks out there).
1 parent a21c2eb commit 6c9b8ad

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs

+21-8
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,10 +19,11 @@ 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);
24-
22+
fn impls_have_common_items(
23+
&self,
24+
impl_items1: &ty::AssociatedItems<'_>,
25+
impl_items2: &ty::AssociatedItems<'_>,
26+
) -> bool {
2527
let mut impl_items1 = &impl_items1;
2628
let mut impl_items2 = &impl_items2;
2729

@@ -121,9 +123,20 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
121123
let ty_def_id = self.tcx.hir().local_def_id(item.hir_id);
122124
let impls = self.tcx.inherent_impls(ty_def_id);
123125

124-
for (i, &impl1_def_id) in impls.iter().enumerate() {
125-
for &impl2_def_id in &impls[(i + 1)..] {
126-
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) {
127140
self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id);
128141
}
129142
}

0 commit comments

Comments
 (0)