Skip to content

Commit 78fd0f6

Browse files
committed
Auto merge of rust-lang#92244 - petrochenkov:alltraits, r=cjgillot
rustc_metadata: Encode list of all crate's traits into metadata While working on rust-lang#88679 I noticed that rustdoc is casually doing something quite expensive, something that is used only for error reporting in rustc - collecting all traits from all crates in the dependency tree. This PR trades some minor extra time spent by metadata encoder in rustc for major gains for rustdoc (and for rustc runs with errors, which execute the `all_traits` query for better diagnostics).
2 parents df96fb1 + 90e3710 commit 78fd0f6

File tree

12 files changed

+95
-112
lines changed

12 files changed

+95
-112
lines changed

Diff for: compiler/rustc_metadata/src/rmeta/decoder.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
13751375
)
13761376
}
13771377

1378+
fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a {
1379+
self.root.traits.decode(self).map(|index| self.local_def_id(index))
1380+
}
1381+
13781382
fn get_implementations_for_trait(
13791383
&self,
13801384
tcx: TyCtxt<'tcx>,

Diff for: compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+26
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ use crate::native_libs;
44

55
use rustc_ast as ast;
66
use rustc_data_structures::stable_map::FxHashMap;
7+
use rustc_hir as hir;
78
use rustc_hir::def::{CtorKind, DefKind};
89
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
910
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
11+
use rustc_hir::itemlikevisit::ItemLikeVisitor;
1012
use rustc_middle::hir::exports::Export;
1113
use rustc_middle::middle::exported_symbols::ExportedSymbol;
1214
use rustc_middle::middle::stability::DeprecationEntry;
@@ -195,6 +197,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
195197

196198
extra_filename => { cdata.root.extra_filename.clone() }
197199

200+
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
201+
198202
implementations_of_trait => {
199203
cdata.get_implementations_for_trait(tcx, Some(other))
200204
}
@@ -285,6 +289,28 @@ pub fn provide(providers: &mut Providers) {
285289
foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect();
286290
Lrc::new(modules)
287291
},
292+
traits_in_crate: |tcx, cnum| {
293+
assert_eq!(cnum, LOCAL_CRATE);
294+
295+
#[derive(Default)]
296+
struct TraitsVisitor {
297+
traits: Vec<DefId>,
298+
}
299+
impl ItemLikeVisitor<'_> for TraitsVisitor {
300+
fn visit_item(&mut self, item: &hir::Item<'_>) {
301+
if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind {
302+
self.traits.push(item.def_id.to_def_id());
303+
}
304+
}
305+
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
306+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
307+
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
308+
}
309+
310+
let mut visitor = TraitsVisitor::default();
311+
tcx.hir().visit_all_item_likes(&mut visitor);
312+
tcx.arena.alloc_slice(&visitor.traits)
313+
},
288314

289315
// Returns a map from a sufficiently visible external item (i.e., an
290316
// external item that is visible from at least one local module) to a

Diff for: compiler/rustc_metadata/src/rmeta/encoder.rs

+37-22
Original file line numberDiff line numberDiff line change
@@ -614,8 +614,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
614614

615615
// Encode the def IDs of impls, for coherence checking.
616616
i = self.position();
617-
let impls = self.encode_impls();
618-
let impl_bytes = self.position() - i;
617+
let (traits, impls) = self.encode_traits_and_impls();
618+
let traits_and_impls_bytes = self.position() - i;
619619

620620
let tcx = self.tcx;
621621

@@ -727,6 +727,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
727727
foreign_modules,
728728
source_map,
729729
impls,
730+
traits,
730731
exported_symbols,
731732
interpret_alloc_index,
732733
tables,
@@ -753,7 +754,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
753754
eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
754755
eprintln!(" native bytes: {}", native_lib_bytes);
755756
eprintln!(" source_map bytes: {}", source_map_bytes);
756-
eprintln!(" impl bytes: {}", impl_bytes);
757+
eprintln!("traits and impls bytes: {}", traits_and_impls_bytes);
757758
eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes);
758759
eprintln!(" def-path table bytes: {}", def_path_table_bytes);
759760
eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes);
@@ -1791,16 +1792,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
17911792
}
17921793

17931794
/// Encodes an index, mapping each trait to its (local) implementations.
1794-
fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
1795-
empty_proc_macro!(self);
1796-
debug!("EncodeContext::encode_impls()");
1795+
fn encode_traits_and_impls(&mut self) -> (Lazy<[DefIndex]>, Lazy<[TraitImpls]>) {
1796+
if self.is_proc_macro {
1797+
return (Lazy::empty(), Lazy::empty());
1798+
}
1799+
debug!("EncodeContext::encode_traits_and_impls()");
17971800
let tcx = self.tcx;
1798-
let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() };
1801+
let mut visitor =
1802+
TraitsAndImplsVisitor { tcx, impls: FxHashMap::default(), traits: Default::default() };
17991803
tcx.hir().visit_all_item_likes(&mut visitor);
18001804

1805+
let mut all_traits = visitor.traits;
18011806
let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
18021807

18031808
// Bring everything into deterministic order for hashing
1809+
all_traits.sort_by_cached_key(|&local_def_index| {
1810+
tcx.hir().def_path_hash(LocalDefId { local_def_index })
1811+
});
18041812
all_impls.sort_by_cached_key(|&(trait_def_id, _)| tcx.def_path_hash(trait_def_id));
18051813

18061814
let all_impls: Vec<_> = all_impls
@@ -1818,7 +1826,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18181826
})
18191827
.collect();
18201828

1821-
self.lazy(&all_impls)
1829+
(self.lazy(&all_traits), self.lazy(&all_impls))
18221830
}
18231831

18241832
// Encodes all symbols exported from this crate into the metadata.
@@ -2040,27 +2048,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
20402048
}
20412049
}
20422050

2043-
struct ImplVisitor<'tcx> {
2051+
struct TraitsAndImplsVisitor<'tcx> {
20442052
tcx: TyCtxt<'tcx>,
2053+
traits: Vec<DefIndex>,
20452054
impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>,
20462055
}
20472056

2048-
impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
2057+
impl<'tcx, 'v> ItemLikeVisitor<'v> for TraitsAndImplsVisitor<'tcx> {
20492058
fn visit_item(&mut self, item: &hir::Item<'_>) {
2050-
if let hir::ItemKind::Impl { .. } = item.kind {
2051-
if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
2052-
let simplified_self_ty = fast_reject::simplify_type(
2053-
self.tcx,
2054-
trait_ref.self_ty(),
2055-
SimplifyParams::No,
2056-
StripReferences::No,
2057-
);
2059+
match item.kind {
2060+
hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
2061+
self.traits.push(item.def_id.local_def_index);
2062+
}
2063+
hir::ItemKind::Impl(..) => {
2064+
if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
2065+
let simplified_self_ty = fast_reject::simplify_type(
2066+
self.tcx,
2067+
trait_ref.self_ty(),
2068+
SimplifyParams::No,
2069+
StripReferences::No,
2070+
);
20582071

2059-
self.impls
2060-
.entry(trait_ref.def_id)
2061-
.or_default()
2062-
.push((item.def_id.local_def_index, simplified_self_ty));
2072+
self.impls
2073+
.entry(trait_ref.def_id)
2074+
.or_default()
2075+
.push((item.def_id.local_def_index, simplified_self_ty));
2076+
}
20632077
}
2078+
_ => {}
20642079
}
20652080
}
20662081

Diff for: compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ crate struct CrateRoot<'tcx> {
222222
diagnostic_items: Lazy<[(Symbol, DefIndex)]>,
223223
native_libraries: Lazy<[NativeLib]>,
224224
foreign_modules: Lazy<[ForeignModule]>,
225+
traits: Lazy<[DefIndex]>,
225226
impls: Lazy<[TraitImpls]>,
226227
interpret_alloc_index: Lazy<[u32]>,
227228
proc_macro_data: Option<ProcMacroData>,

Diff for: compiler/rustc_middle/src/query/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1609,11 +1609,11 @@ rustc_queries! {
16091609
desc { "fetching all foreign CrateNum instances" }
16101610
}
16111611

1612-
/// A vector of every trait accessible in the whole crate
1613-
/// (i.e., including those from subcrates). This is used only for
1614-
/// error reporting.
1615-
query all_traits(_: ()) -> &'tcx [DefId] {
1616-
desc { "fetching all foreign and local traits" }
1612+
/// A list of all traits in a crate, used by rustdoc and error reporting.
1613+
/// NOTE: Not named just `traits` due to a naming conflict.
1614+
query traits_in_crate(_: CrateNum) -> &'tcx [DefId] {
1615+
desc { "fetching all traits in a crate" }
1616+
separate_provide_extern
16171617
}
16181618

16191619
/// The list of symbols exported from the given crate.

Diff for: compiler/rustc_middle/src/ty/context.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,12 @@ impl<'tcx> TyCtxt<'tcx> {
15771577
pub fn const_eval_limit(self) -> Limit {
15781578
self.limits(()).const_eval_limit
15791579
}
1580+
1581+
pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
1582+
iter::once(LOCAL_CRATE)
1583+
.chain(self.crates(()).iter().copied())
1584+
.flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
1585+
}
15801586
}
15811587

15821588
/// A trait implemented for all `X<'a>` types that can be safely and

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1567,14 +1567,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
15671567
self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some)
15681568
};
15691569
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
1570-
let all_traits = self.tcx.all_traits(());
1571-
let traits_with_same_path: std::collections::BTreeSet<_> = all_traits
1572-
.iter()
1573-
.filter(|trait_def_id| **trait_def_id != trait_ref.def_id())
1574-
.filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path)
1570+
let traits_with_same_path: std::collections::BTreeSet<_> = self
1571+
.tcx
1572+
.all_traits()
1573+
.filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
1574+
.filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path)
15751575
.collect();
15761576
for trait_with_same_path in traits_with_same_path {
1577-
if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) {
1577+
if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
15781578
let impl_span = self.tcx.def_span(impl_def_id);
15791579
err.span_help(impl_span, "trait impl with same name found");
15801580
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);

Diff for: compiler/rustc_typeck/src/check/method/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod prelude2021;
77
pub mod probe;
88
mod suggest;
99

10-
pub use self::suggest::{SelfSource, TraitInfo};
10+
pub use self::suggest::SelfSource;
1111
pub use self::CandidateSource::*;
1212
pub use self::MethodError::*;
1313

@@ -31,7 +31,6 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
3131
use self::probe::{IsSuggestion, ProbeScope};
3232

3333
pub fn provide(providers: &mut ty::query::Providers) {
34-
suggest::provide(providers);
3534
probe::provide(providers);
3635
}
3736

Diff for: compiler/rustc_typeck/src/check/method/suggest.rs

+5-71
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use crate::check::FnCtxt;
55
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
66
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
77
use rustc_hir as hir;
8-
use rustc_hir::def::{DefKind, Namespace, Res};
9-
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
8+
use rustc_hir::def::Namespace;
9+
use rustc_hir::def_id::{DefId, LocalDefId};
1010
use rustc_hir::lang_items::LangItem;
1111
use rustc_hir::{ExprKind, Node, QPath};
1212
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -1922,76 +1922,10 @@ impl Ord for TraitInfo {
19221922
}
19231923
}
19241924

1925-
/// Retrieves all traits in this crate and any dependent crates.
1925+
/// Retrieves all traits in this crate and any dependent crates,
1926+
/// and wraps them into `TraitInfo` for custom sorting.
19261927
pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
1927-
tcx.all_traits(()).iter().map(|&def_id| TraitInfo { def_id }).collect()
1928-
}
1929-
1930-
/// Computes all traits in this crate and any dependent crates.
1931-
fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] {
1932-
use hir::itemlikevisit;
1933-
1934-
let mut traits = vec![];
1935-
1936-
// Crate-local:
1937-
1938-
struct Visitor<'a> {
1939-
traits: &'a mut Vec<DefId>,
1940-
}
1941-
1942-
impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> {
1943-
fn visit_item(&mut self, i: &'v hir::Item<'v>) {
1944-
match i.kind {
1945-
hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
1946-
self.traits.push(i.def_id.to_def_id());
1947-
}
1948-
_ => (),
1949-
}
1950-
}
1951-
1952-
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
1953-
1954-
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
1955-
1956-
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
1957-
}
1958-
1959-
tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits });
1960-
1961-
// Cross-crate:
1962-
1963-
let mut external_mods = FxHashSet::default();
1964-
fn handle_external_res(
1965-
tcx: TyCtxt<'_>,
1966-
traits: &mut Vec<DefId>,
1967-
external_mods: &mut FxHashSet<DefId>,
1968-
res: Res<!>,
1969-
) {
1970-
match res {
1971-
Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
1972-
traits.push(def_id);
1973-
}
1974-
Res::Def(DefKind::Mod, def_id) => {
1975-
if !external_mods.insert(def_id) {
1976-
return;
1977-
}
1978-
for child in tcx.item_children(def_id).iter() {
1979-
handle_external_res(tcx, traits, external_mods, child.res)
1980-
}
1981-
}
1982-
_ => {}
1983-
}
1984-
}
1985-
for &cnum in tcx.crates(()).iter() {
1986-
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
1987-
handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1988-
}
1989-
1990-
tcx.arena.alloc_from_iter(traits)
1991-
}
1992-
1993-
pub fn provide(providers: &mut ty::query::Providers) {
1994-
providers.all_traits = compute_all_traits;
1928+
tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
19951929
}
19961930

19971931
fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option<Span>, bool) {

Diff for: src/librustdoc/clean/blanket_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
1919

2020
trace!("get_blanket_impls({:?})", ty);
2121
let mut impls = Vec::new();
22-
for &trait_def_id in self.cx.tcx.all_traits(()).iter() {
22+
for trait_def_id in self.cx.tcx.all_traits() {
2323
if !self.cx.cache.access_levels.is_public(trait_def_id)
2424
|| self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
2525
{

Diff for: src/librustdoc/core.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,8 @@ crate fn run_global_ctxt(
369369
impl_trait_bounds: Default::default(),
370370
generated_synthetics: Default::default(),
371371
auto_traits: tcx
372-
.all_traits(())
373-
.iter()
374-
.cloned()
375-
.filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
372+
.all_traits()
373+
.filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
376374
.collect(),
377375
module_trait_cache: FxHashMap::default(),
378376
cache: Cache::new(access_levels, render_options.document_private),

Diff for: src/librustdoc/passes/collect_trait_impls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
129129
// `tcx.crates(())` doesn't include the local crate, and `tcx.all_trait_implementations`
130130
// doesn't work with it anyway, so pull them from the HIR map instead
131131
let mut extra_attrs = Vec::new();
132-
for &trait_did in cx.tcx.all_traits(()).iter() {
132+
for trait_did in cx.tcx.all_traits() {
133133
for &impl_did in cx.tcx.hir().trait_impls(trait_did) {
134134
let impl_did = impl_did.to_def_id();
135135
cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| {

0 commit comments

Comments
 (0)