about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2020-10-11 03:19:14 +0900
committerGitHub <noreply@github.com>2020-10-11 03:19:14 +0900
commit8752b43900a82f8f7c0f08c74a3f360148b91e5a (patch)
tree980085f80e636accd9fe25b246f04d19c55c15b4
parent83685880b6de32e9781bea09d3d54decd195a9dd (diff)
parent217d6f9741819aedfe22e6d3ec9cca6e4a49f77d (diff)
downloadrust-8752b43900a82f8f7c0f08c74a3f360148b91e5a.tar.gz
rust-8752b43900a82f8f7c0f08c74a3f360148b91e5a.zip
Rollup merge of #77754 - bugadani:find_map_relevant_impl, r=matthewjasper
Add TraitDef::find_map_relevant_impl

This PR adds a method to `TraitDef`. While `for_each_relevant_impl` covers the general use case, sometimes it's not necessary to scan through all the relevant implementations, so this PR introduces a new method, `find_map_relevant_impl`. I've also replaced the `for_each_relevant_impl` calls where possible.

I'm hoping for a tiny bit of efficiency gain here and there.
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs28
-rw-r--r--compiler/rustc_middle/src/ty/util.rs6
-rw-r--r--compiler/rustc_mir/src/transform/check_const_item_mutation.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs12
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs16
5 files changed, 38 insertions, 27 deletions
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 9d5b558234b..86476dffc03 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -123,10 +123,26 @@ impl<'tcx> TyCtxt<'tcx> {
         self_ty: Ty<'tcx>,
         mut f: F,
     ) {
+        let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| {
+            f(did);
+            None
+        });
+    }
+
+    /// Applies function to every impl that could possibly match the self type `self_ty` and returns
+    /// the first non-none value.
+    pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
+        self,
+        def_id: DefId,
+        self_ty: Ty<'tcx>,
+        mut f: F,
+    ) -> Option<T> {
         let impls = self.trait_impls_of(def_id);
 
         for &impl_def_id in impls.blanket_impls.iter() {
-            f(impl_def_id);
+            if let result @ Some(_) = f(impl_def_id) {
+                return result;
+            }
         }
 
         // simplify_type(.., false) basically replaces type parameters and
@@ -157,14 +173,20 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
-                    f(impl_def_id);
+                    if let result @ Some(_) = f(impl_def_id) {
+                        return result;
+                    }
                 }
             }
         } else {
             for &impl_def_id in impls.non_blanket_impls.values().flatten() {
-                f(impl_def_id);
+                if let result @ Some(_) = f(impl_def_id) {
+                    return result;
+                }
             }
         }
+
+        None
     }
 
     /// Returns an iterator containing all impls
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4127b6535bc..d8ea2f67393 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -346,14 +346,14 @@ impl<'tcx> TyCtxt<'tcx> {
         let drop_trait = self.lang_items().drop_trait()?;
         self.ensure().coherent_trait(drop_trait);
 
-        let mut dtor_did = None;
         let ty = self.type_of(adt_did);
-        self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
+        let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
             if let Some(item) = self.associated_items(impl_did).in_definition_order().next() {
                 if validate(self, impl_did).is_ok() {
-                    dtor_did = Some(item.def_id);
+                    return Some(item.def_id);
                 }
             }
+            None
         });
 
         Some(ty::Destructor { did: dtor_did? })
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
index 4d4e9b98917..26993a6b941 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -34,7 +34,6 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
 
     fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
         let def_id = self.is_const_item(local)?;
-        let mut any_dtor = |_tcx, _def_id| Ok(());
 
         // We avoid linting mutation of a const item if the const's type has a
         // Drop impl. The Drop logic observes the mutation which was performed.
@@ -54,7 +53,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
         //
         //     #[const_mutation_allowed]
         //     pub const LOG: Log = Log { msg: "" };
-        match self.tcx.calculate_dtor(def_id, &mut any_dtor) {
+        match self.tcx.calculate_dtor(def_id, &mut |_, _| Ok(())) {
             Some(_) => None,
             None => Some(def_id),
         }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index cb3de57cfed..05e3ed34351 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1384,17 +1384,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) {
         let get_trait_impl = |trait_def_id| {
-            let mut trait_impl = None;
-            self.tcx.for_each_relevant_impl(
+            self.tcx.find_map_relevant_impl(
                 trait_def_id,
                 trait_ref.skip_binder().self_ty(),
-                |impl_def_id| {
-                    if trait_impl.is_none() {
-                        trait_impl = Some(impl_def_id);
-                    }
-                },
-            );
-            trait_impl
+                |impl_def_id| Some(impl_def_id),
+            )
         };
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
         let all_traits = self.tcx.all_traits(LOCAL_CRATE);
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 5b5624298a4..34eac31890c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -650,14 +650,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
     let ty = cx.tcx.type_of(type_);
     let iter = in_scope_traits.iter().flat_map(|&trait_| {
         trace!("considering explicit impl for trait {:?}", trait_);
-        let mut saw_impl = false;
-        // Look at each trait implementation to see if it's an impl for `did`
-        cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| {
-            // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
-            if saw_impl {
-                return;
-            }
 
+        // Look at each trait implementation to see if it's an impl for `did`
+        cx.tcx.find_map_relevant_impl(trait_, ty, |impl_| {
             let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
             let impl_type = trait_ref.self_ty();
@@ -668,7 +663,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
                 type_
             );
             // Fast path: if this is a primitive simple `==` will work
-            saw_impl = impl_type == ty
+            let saw_impl = impl_type == ty
                 || match impl_type.kind() {
                     // Check if these are the same def_id
                     ty::Adt(def, _) => {
@@ -678,8 +673,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
                     ty::Foreign(def_id) => *def_id == type_,
                     _ => false,
                 };
-        });
-        if saw_impl { Some(trait_) } else { None }
+
+            if saw_impl { Some(trait_) } else { None }
+        })
     });
     iter.collect()
 }