From 7993ddd89d8d2e0754bf9b12756573f56b76e254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 9 Oct 2020 15:28:32 +0200 Subject: [PATCH] Add find_map_relevant_impl --- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_middle/src/ty/trait_def.rs | 35 +++++++++++++++++++ compiler/rustc_middle/src/ty/util.rs | 8 ++--- .../transform/check_const_item_mutation.rs | 3 +- .../src/traits/error_reporting/mod.rs | 12 ++----- compiler/rustc_typeck/src/check/mod.rs | 2 +- .../passes/collect_intra_doc_links.rs | 16 ++++----- 7 files changed, 51 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 60705f68681..05b8dad3097 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -94,7 +94,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; - tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) + tcx.calculate_dtor(def_id, |_,_| Ok(())) } variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 9d5b558234b..5599216c316 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -167,6 +167,41 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// 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 Option>( + self, + def_id: DefId, + self_ty: Ty<'tcx>, + f: F, + ) -> Option { + let impls = self.trait_impls_of(def_id); + + for &impl_def_id in impls.blanket_impls.iter() { + if let result @ Some(_) = f(impl_def_id) { + return result; + } + } + + 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 { + if let result @ Some(_) = f(impl_def_id) { + return result; + } + } + } + } else { + for &impl_def_id in impls.non_blanket_impls.values().flatten() { + if let result @ Some(_) = f(impl_def_id) { + return result; + } + } + } + + None + } + /// Returns an iterator containing all impls pub fn all_impls(self, def_id: DefId) -> impl Iterator + 'tcx { let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4127b6535bc..5ac12dfa993 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -341,19 +341,19 @@ impl<'tcx> TyCtxt<'tcx> { pub fn calculate_dtor( self, adt_did: DefId, - validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>, + validate: impl Fn(Self, DefId) -> Result<(), ErrorReported>, ) -> Option { 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..fb89b36060a 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 { 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, |_, _| 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/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 97172d391ba..1cb6ae21a47 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -264,7 +264,7 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) + tcx.calculate_dtor(def_id, dropck::check_drop_impl) } /// If this `DefId` is a "primary tables entry", returns diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index b9be3e2f92b..ab399107661 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() }