Skip to content

Commit a9d7810

Browse files
committed
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`.
1 parent 617d3d6 commit a9d7810

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

compiler/rustc_middle/src/ty/trait_def.rs

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::traits::specialization_graph;
22
use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
33
use crate::ty::visit::TypeVisitableExt;
4-
use crate::ty::{Ident, Ty, TyCtxt};
4+
use crate::ty::{Ident, Ty, TyCtxt, TyKind};
55
use hir::def_id::LOCAL_CRATE;
66
use rustc_hir as hir;
77
use rustc_hir::def_id::DefId;
@@ -77,6 +77,10 @@ pub struct TraitImpls {
7777
blanket_impls: Vec<DefId>,
7878
/// Impls indexed by their simplified self type, for fast lookup.
7979
non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>,
80+
81+
/// Impls for references to simplifiable types, indexed by the referenced simplified type, for
82+
/// fast lookup.
83+
impls_for_ref_x: FxIndexMap<SimplifiedType, Vec<DefId>>,
8084
}
8185

8286
impl TraitImpls {
@@ -144,14 +148,10 @@ impl<'tcx> TyCtxt<'tcx> {
144148
//
145149
// If we want to be faster, we could have separate queries for
146150
// blanket and non-blanket impls, and compare them separately.
147-
let impls = self.trait_impls_of(trait_def_id);
148-
149-
for &impl_def_id in impls.blanket_impls.iter() {
150-
f(impl_def_id);
151-
}
152151

153-
// Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
154-
// `TreatParams::AsCandidateKey` while actually adding them.
152+
// Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` and
153+
// `impls_for_ref_x`, while using `TreatParams::AsCandidateKey` while actually adding them
154+
// (in `trait_impls_of_provider`).
155155
let treat_params = match treat_projections {
156156
TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup,
157157
TreatProjections::ForLookup => TreatParams::ForLookup,
@@ -161,13 +161,36 @@ impl<'tcx> TyCtxt<'tcx> {
161161
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
162162
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
163163
if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
164+
let impls = self.trait_impls_of(trait_def_id);
165+
166+
for &impl_def_id in impls.blanket_impls.iter() {
167+
f(impl_def_id);
168+
}
169+
164170
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
165171
for &impl_def_id in impls {
166172
f(impl_def_id);
167173
}
168174
}
175+
176+
// We separate impls for references to simplifiable types to allow for faster lookups:
177+
// the set of possibly matching impls is smaller than if we stored them all as
178+
// `SimplifiedType::RefSimplifiedType`.
179+
if let TyKind::Ref(_, ref_ty, _) = self_ty.kind() {
180+
if let Some(ref_simp) = fast_reject::simplify_type(self, *ref_ty, treat_params) {
181+
if let Some(impls) = impls.impls_for_ref_x.get(&ref_simp) {
182+
for &impl_def_id in impls {
183+
f(impl_def_id);
184+
}
185+
}
186+
} else {
187+
for &impl_def_id in impls.impls_for_ref_x.values().flatten() {
188+
f(impl_def_id);
189+
}
190+
}
191+
}
169192
} else {
170-
for &impl_def_id in impls.non_blanket_impls.values().flatten() {
193+
for impl_def_id in self.all_impls(trait_def_id) {
171194
f(impl_def_id);
172195
}
173196
}
@@ -193,9 +216,14 @@ impl<'tcx> TyCtxt<'tcx> {
193216
///
194217
/// `trait_def_id` MUST BE the `DefId` of a trait.
195218
pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
196-
let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(trait_def_id);
197-
198-
blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned()
219+
let TraitImpls { blanket_impls, non_blanket_impls, impls_for_ref_x } =
220+
self.trait_impls_of(trait_def_id);
221+
222+
blanket_impls
223+
.iter()
224+
.chain(non_blanket_impls.iter().flat_map(|(_, v)| v))
225+
.chain(impls_for_ref_x.iter().flat_map(|(_, v)| v))
226+
.copied()
199227
}
200228
}
201229

@@ -231,6 +259,17 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
231259
continue;
232260
}
233261

262+
// Store impls for references to simplifiable types separately from other impls, for faster
263+
// lookups.
264+
if let TyKind::Ref(_, ref_ty, _) = impl_self_ty.kind() {
265+
if let Some(simplified_ref_ty) =
266+
fast_reject::simplify_type(tcx, *ref_ty, TreatParams::AsCandidateKey)
267+
{
268+
impls.impls_for_ref_x.entry(simplified_ref_ty).or_default().push(impl_def_id);
269+
continue;
270+
}
271+
}
272+
234273
if let Some(simplified_self_ty) =
235274
fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey)
236275
{

0 commit comments

Comments
 (0)