From a9d7810bd0295bebf385906f662fdad1ea626005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 26 Dec 2022 21:43:56 +0000 Subject: [PATCH 1/3] separate impls for refs to simplifiable types Separate impls for references to simplifiable types to allow for faster lookups: the set of possibly matching impls is smaller than if we stored them all as `SimplifiedType::RefSimplifiedType`. --- compiler/rustc_middle/src/ty/trait_def.rs | 63 ++++++++++++++++++----- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index e61037e5ea86f..333cdb50c23dd 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,7 +1,7 @@ use crate::traits::specialization_graph; use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; use crate::ty::visit::TypeVisitableExt; -use crate::ty::{Ident, Ty, TyCtxt}; +use crate::ty::{Ident, Ty, TyCtxt, TyKind}; use hir::def_id::LOCAL_CRATE; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -77,6 +77,10 @@ pub struct TraitImpls { blanket_impls: Vec, /// Impls indexed by their simplified self type, for fast lookup. non_blanket_impls: FxIndexMap>, + + /// Impls for references to simplifiable types, indexed by the referenced simplified type, for + /// fast lookup. + impls_for_ref_x: FxIndexMap>, } impl TraitImpls { @@ -144,14 +148,10 @@ impl<'tcx> TyCtxt<'tcx> { // // If we want to be faster, we could have separate queries for // blanket and non-blanket impls, and compare them separately. - let impls = self.trait_impls_of(trait_def_id); - - for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); - } - // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using - // `TreatParams::AsCandidateKey` while actually adding them. + // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` and + // `impls_for_ref_x`, while using `TreatParams::AsCandidateKey` while actually adding them + // (in `trait_impls_of_provider`). let treat_params = match treat_projections { TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup, TreatProjections::ForLookup => TreatParams::ForLookup, @@ -161,13 +161,36 @@ impl<'tcx> TyCtxt<'tcx> { // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option`, `Vec`, `ConcreteType` and so on. if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) { + let impls = self.trait_impls_of(trait_def_id); + + for &impl_def_id in impls.blanket_impls.iter() { + f(impl_def_id); + } + if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { f(impl_def_id); } } + + // We separate impls for references to simplifiable types to allow for faster lookups: + // the set of possibly matching impls is smaller than if we stored them all as + // `SimplifiedType::RefSimplifiedType`. + if let TyKind::Ref(_, ref_ty, _) = self_ty.kind() { + if let Some(ref_simp) = fast_reject::simplify_type(self, *ref_ty, treat_params) { + if let Some(impls) = impls.impls_for_ref_x.get(&ref_simp) { + for &impl_def_id in impls { + f(impl_def_id); + } + } + } else { + for &impl_def_id in impls.impls_for_ref_x.values().flatten() { + f(impl_def_id); + } + } + } } else { - for &impl_def_id in impls.non_blanket_impls.values().flatten() { + for impl_def_id in self.all_impls(trait_def_id) { f(impl_def_id); } } @@ -193,9 +216,14 @@ impl<'tcx> TyCtxt<'tcx> { /// /// `trait_def_id` MUST BE the `DefId` of a trait. pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator + 'tcx { - let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(trait_def_id); - - blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned() + let TraitImpls { blanket_impls, non_blanket_impls, impls_for_ref_x } = + self.trait_impls_of(trait_def_id); + + blanket_impls + .iter() + .chain(non_blanket_impls.iter().flat_map(|(_, v)| v)) + .chain(impls_for_ref_x.iter().flat_map(|(_, v)| v)) + .copied() } } @@ -231,6 +259,17 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait continue; } + // Store impls for references to simplifiable types separately from other impls, for faster + // lookups. + if let TyKind::Ref(_, ref_ty, _) = impl_self_ty.kind() { + if let Some(simplified_ref_ty) = + fast_reject::simplify_type(tcx, *ref_ty, TreatParams::AsCandidateKey) + { + impls.impls_for_ref_x.entry(simplified_ref_ty).or_default().push(impl_def_id); + continue; + } + } + if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey) { From f2b58f3da22033632618fdd828f763dbb19433e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 26 Dec 2022 21:45:58 +0000 Subject: [PATCH 2/3] clean-up `for_each_impl` to use `all_impls` handle `impls_for_ref_x` and reduce duplication when iterating over all impls. also: use it in `for_each_relevant_impl_treating_projections` --- compiler/rustc_middle/src/ty/trait_def.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 333cdb50c23dd..a2157fc05d548 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -105,18 +105,10 @@ impl<'tcx> TraitDef { impl<'tcx> TyCtxt<'tcx> { /// `trait_def_id` MUST BE the `DefId` of a trait. - pub fn for_each_impl(self, trait_def_id: DefId, mut f: F) { - let impls = self.trait_impls_of(trait_def_id); - - for &impl_def_id in impls.blanket_impls.iter() { + pub fn for_each_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) { + for impl_def_id in self.all_impls(trait_def_id) { f(impl_def_id); } - - for v in impls.non_blanket_impls.values() { - for &impl_def_id in v { - f(impl_def_id); - } - } } /// Iterate over every impl that could possibly match the self type `self_ty`. @@ -190,9 +182,7 @@ impl<'tcx> TyCtxt<'tcx> { } } } else { - for impl_def_id in self.all_impls(trait_def_id) { - f(impl_def_id); - } + self.for_each_impl(trait_def_id, f); } } From 030f9bb8b266765e5b20354f54ee534e63ab7279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 26 Dec 2022 21:48:13 +0000 Subject: [PATCH 3/3] return refs to simplifiable types in `non_blanket_impls_for_ty` for users of the API, we return impls from `non_blanket_impls` and `impls_for_ref_x` as if they weren't separated. --- compiler/rustc_middle/src/ty/trait_def.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index a2157fc05d548..30180fe0293e2 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -193,8 +193,24 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator + 'tcx { let impls = self.trait_impls_of(trait_def_id); - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) { - if let Some(impls) = impls.non_blanket_impls.get(&simp) { + + // Non-blanket impls are grouped into two different maps: + // 1) impls for references to simplifiable types + if let TyKind::Ref(_, ref_ty, _) = self_ty.kind() { + if let Some(simplified_ref_ty) = + fast_reject::simplify_type(self, *ref_ty, TreatParams::AsCandidateKey) + { + if let Some(impls) = impls.impls_for_ref_x.get(&simplified_ref_ty) { + return impls.iter().copied(); + } + } + } + + // 2) the other non-blanket impls + if let Some(simplified_self_ty) = + fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) + { + if let Some(impls) = impls.non_blanket_impls.get(&simplified_self_ty) { return impls.iter().copied(); } }