about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-28 03:58:32 +0000
committerbors <bors@rust-lang.org>2020-10-28 03:58:32 +0000
commit2eb4fc800aaf5006f89af3af591e2aa34f469d81 (patch)
treebba217a86f43117a0eafe735d50f388481ea715c
parentdb241bb0c8d257e13c1560f6250e49879477039e (diff)
parent6c9b8ada0c269fdbfd36cf66060bab9898824dd2 (diff)
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.
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs35
2 files changed, 32 insertions, 7 deletions
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 845fa8a47ae..a400b85cdb7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -266,6 +266,10 @@ impl<'tcx> AssociatedItems<'tcx> {
         self.items.iter().map(|(_, v)| *v)
     }
 
+    pub fn len(&self) -> usize {
+        self.items.len()
+    }
+
     /// Returns an iterator over all associated items with the given name, ignoring hygiene.
     pub fn filter_by_name_unhygienic(
         &self,
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index be77d049cae..ce157f809ef 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -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);
@@ -18,9 +19,18 @@ 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;
+
+        // Performance optimization: iterate over the smaller list
+        if impl_items1.len() > impl_items2.len() {
+            std::mem::swap(&mut impl_items1, &mut impl_items2);
+        }
 
         for item1 in impl_items1.in_definition_order() {
             let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| {
@@ -113,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);
                         }
                     }