Skip to content

Commit

Permalink
Precompute the associated items
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
est31 committed Oct 25, 2020
1 parent a21c2eb commit 6c9b8ad
Showing 1 changed file with 21 additions and 8 deletions.
29 changes: 21 additions & 8 deletions compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, TyCtxt};
use rustc_trait_selection::traits::{self, SkipLeakCheck};
use smallvec::SmallVec;

pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) {
assert_eq!(crate_num, LOCAL_CRATE);
Expand All @@ -18,10 +19,11 @@ struct InherentOverlapChecker<'tcx> {
impl InherentOverlapChecker<'tcx> {
/// Checks whether any associated items in impls 1 and 2 share the same identifier and
/// namespace.
fn impls_have_common_items(&self, impl1: DefId, impl2: DefId) -> bool {
let impl_items1 = self.tcx.associated_items(impl1);
let impl_items2 = self.tcx.associated_items(impl2);

fn impls_have_common_items(
&self,
impl_items1: &ty::AssociatedItems<'_>,
impl_items2: &ty::AssociatedItems<'_>,
) -> bool {
let mut impl_items1 = &impl_items1;
let mut impl_items2 = &impl_items2;

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

for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i + 1)..] {
if self.impls_have_common_items(impl1_def_id, impl2_def_id) {
// If there is only one inherent impl block,
// there is nothing to overlap check it with
if impls.len() <= 1 {
return;
}

let impls_items = impls
.iter()
.map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
.collect::<SmallVec<[_; 8]>>();

for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
if self.impls_have_common_items(impl_items1, impl_items2) {
self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id);
}
}
Expand Down

0 comments on commit 6c9b8ad

Please sign in to comment.