Auto merge of #75008 - eddyb:rmeta-indexed-trait-impls, r=nikomatsakis
rustc_metadata: track the simplified Self type for every trait impl. For the `traits_impls_of` query, we index the impls by `fast_reject::SimplifiedType` (a "shallow type"), which allows some simple cases like `impl Trait<..> for Foo<..>` to be efficiently iterated over, by e.g. `for_each_relevant_impl`. This PR encodes the `fast_reject::SimplifiedType` cross-crate to avoid needing to deserialize the `Self` type of every `impl` in order to simplify it - the simplification itself should be cheap, but the deserialization is less so. We could go further from here and make loading the list of impls lazy, for a given simplified `Self` type, but that would have more complicated implications for performance, and this PR doesn't do anything in that regard. r? @nikomatsakis cc @Mark-Simulacrum
This commit is contained in:
commit
3cfc7fe78e
@ -78,7 +78,8 @@
|
|||||||
/// Trait impl data.
|
/// Trait impl data.
|
||||||
/// FIXME: Used only from queries and can use query cache,
|
/// FIXME: Used only from queries and can use query cache,
|
||||||
/// so pre-decoding can probably be avoided.
|
/// so pre-decoding can probably be avoided.
|
||||||
trait_impls: FxHashMap<(u32, DefIndex), Lazy<[DefIndex]>>,
|
trait_impls:
|
||||||
|
FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>>,
|
||||||
/// Proc macro descriptions for this crate, if it's a proc macro crate.
|
/// Proc macro descriptions for this crate, if it's a proc macro crate.
|
||||||
raw_proc_macros: Option<&'static [ProcMacro]>,
|
raw_proc_macros: Option<&'static [ProcMacro]>,
|
||||||
/// Source maps for code from the crate.
|
/// Source maps for code from the crate.
|
||||||
@ -1289,7 +1290,7 @@ fn get_implementations_for_trait(
|
|||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
filter: Option<DefId>,
|
filter: Option<DefId>,
|
||||||
) -> &'tcx [DefId] {
|
) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
|
||||||
if self.root.is_proc_macro_crate() {
|
if self.root.is_proc_macro_crate() {
|
||||||
// proc-macro crates export no trait impls.
|
// proc-macro crates export no trait impls.
|
||||||
return &[];
|
return &[];
|
||||||
@ -1305,16 +1306,20 @@ fn get_implementations_for_trait(
|
|||||||
|
|
||||||
if let Some(filter) = filter {
|
if let Some(filter) = filter {
|
||||||
if let Some(impls) = self.trait_impls.get(&filter) {
|
if let Some(impls) = self.trait_impls.get(&filter) {
|
||||||
tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx)))
|
tcx.arena.alloc_from_iter(
|
||||||
|
impls.decode(self).map(|(idx, simplified_self_ty)| {
|
||||||
|
(self.local_def_id(idx), simplified_self_ty)
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tcx.arena.alloc_from_iter(
|
tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| {
|
||||||
self.trait_impls
|
impls
|
||||||
.values()
|
.decode(self)
|
||||||
.flat_map(|impls| impls.decode(self).map(|idx| self.local_def_id(idx))),
|
.map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
|
||||||
)
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1610,7 +1610,7 @@ fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(trait_def_id, mut impls)| {
|
.map(|(trait_def_id, mut impls)| {
|
||||||
// Bring everything into deterministic order for hashing
|
// Bring everything into deterministic order for hashing
|
||||||
impls.sort_by_cached_key(|&index| {
|
impls.sort_by_cached_key(|&(index, _)| {
|
||||||
tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index })
|
tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index })
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1852,7 +1852,7 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
|
|||||||
|
|
||||||
struct ImplVisitor<'tcx> {
|
struct ImplVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impls: FxHashMap<DefId, Vec<DefIndex>>,
|
impls: FxHashMap<DefId, Vec<(DefIndex, Option<ty::fast_reject::SimplifiedType>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
|
impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
|
||||||
@ -1860,7 +1860,13 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
|
|||||||
if let hir::ItemKind::Impl { .. } = item.kind {
|
if let hir::ItemKind::Impl { .. } = item.kind {
|
||||||
let impl_id = self.tcx.hir().local_def_id(item.hir_id);
|
let impl_id = self.tcx.hir().local_def_id(item.hir_id);
|
||||||
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id.to_def_id()) {
|
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id.to_def_id()) {
|
||||||
self.impls.entry(trait_ref.def_id).or_default().push(impl_id.local_def_index);
|
let simplified_self_ty =
|
||||||
|
ty::fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), false);
|
||||||
|
|
||||||
|
self.impls
|
||||||
|
.entry(trait_ref.def_id)
|
||||||
|
.or_default()
|
||||||
|
.push((impl_id.local_def_index, simplified_self_ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ macro_rules! Lazy {
|
|||||||
#[derive(RustcEncodable, RustcDecodable)]
|
#[derive(RustcEncodable, RustcDecodable)]
|
||||||
crate struct TraitImpls {
|
crate struct TraitImpls {
|
||||||
trait_id: (u32, DefIndex),
|
trait_id: (u32, DefIndex),
|
||||||
impls: Lazy<[DefIndex]>,
|
impls: Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define `LazyTables` and `TableBuilders` at the same time.
|
/// Define `LazyTables` and `TableBuilders` at the same time.
|
||||||
|
@ -1125,11 +1125,11 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
|
|||||||
|
|
||||||
TypeChecking {
|
TypeChecking {
|
||||||
query implementations_of_trait(_: (CrateNum, DefId))
|
query implementations_of_trait(_: (CrateNum, DefId))
|
||||||
-> &'tcx [DefId] {
|
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
|
||||||
desc { "looking up implementations of a trait in a crate" }
|
desc { "looking up implementations of a trait in a crate" }
|
||||||
}
|
}
|
||||||
query all_trait_implementations(_: CrateNum)
|
query all_trait_implementations(_: CrateNum)
|
||||||
-> &'tcx [DefId] {
|
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
|
||||||
desc { "looking up all (?) trait implementations" }
|
desc { "looking up all (?) trait implementations" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,32 +187,38 @@ pub(super) fn all_local_trait_impls<'tcx>(
|
|||||||
pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls {
|
pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls {
|
||||||
let mut impls = TraitImpls::default();
|
let mut impls = TraitImpls::default();
|
||||||
|
|
||||||
{
|
// Traits defined in the current crate can't have impls in upstream
|
||||||
let mut add_impl = |impl_def_id: DefId| {
|
// crates, so we don't bother querying the cstore.
|
||||||
let impl_self_ty = tcx.type_of(impl_def_id);
|
if !trait_id.is_local() {
|
||||||
if impl_def_id.is_local() && impl_self_ty.references_error() {
|
for &cnum in tcx.crates().iter() {
|
||||||
return;
|
for &(impl_def_id, simplified_self_ty) in
|
||||||
}
|
tcx.implementations_of_trait((cnum, trait_id)).iter()
|
||||||
|
{
|
||||||
if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) {
|
if let Some(simplified_self_ty) = simplified_self_ty {
|
||||||
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
|
impls
|
||||||
} else {
|
.non_blanket_impls
|
||||||
impls.blanket_impls.push(impl_def_id);
|
.entry(simplified_self_ty)
|
||||||
}
|
.or_default()
|
||||||
};
|
.push(impl_def_id);
|
||||||
|
} else {
|
||||||
// Traits defined in the current crate can't have impls in upstream
|
impls.blanket_impls.push(impl_def_id);
|
||||||
// crates, so we don't bother querying the cstore.
|
|
||||||
if !trait_id.is_local() {
|
|
||||||
for &cnum in tcx.crates().iter() {
|
|
||||||
for &def_id in tcx.implementations_of_trait((cnum, trait_id)).iter() {
|
|
||||||
add_impl(def_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for &hir_id in tcx.hir().trait_impls(trait_id) {
|
for &hir_id in tcx.hir().trait_impls(trait_id) {
|
||||||
add_impl(tcx.hir().local_def_id(hir_id).to_def_id());
|
let impl_def_id = tcx.hir().local_def_id(hir_id).to_def_id();
|
||||||
|
|
||||||
|
let impl_self_ty = tcx.type_of(impl_def_id);
|
||||||
|
if impl_self_ty.references_error() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) {
|
||||||
|
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
|
||||||
|
} else {
|
||||||
|
impls.blanket_impls.push(impl_def_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
|
|||||||
let mut new_items = Vec::new();
|
let mut new_items = Vec::new();
|
||||||
|
|
||||||
for &cnum in cx.tcx.crates().iter() {
|
for &cnum in cx.tcx.crates().iter() {
|
||||||
for &did in cx.tcx.all_trait_implementations(cnum).iter() {
|
for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
|
||||||
inline::build_impl(cx, did, None, &mut new_items);
|
inline::build_impl(cx, did, None, &mut new_items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user