Skip to content

Commit 5acd1f9

Browse files
committed
rustdoc: Introduce a resolver cache for sharing data between early doc link resolution and later passes
1 parent e012a19 commit 5acd1f9

File tree

10 files changed

+290
-259
lines changed

10 files changed

+290
-259
lines changed

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
1010
use rustc_middle::hir::exports::Export;
1111
use rustc_middle::middle::exported_symbols::ExportedSymbol;
1212
use rustc_middle::middle::stability::DeprecationEntry;
13+
use rustc_middle::ty::fast_reject::SimplifiedType;
1314
use rustc_middle::ty::query::{ExternProviders, Providers};
1415
use rustc_middle::ty::{self, TyCtxt, Visibility};
1516
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
@@ -192,8 +193,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
192193
extra_filename => { cdata.root.extra_filename.clone() }
193194

194195
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
195-
all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }
196-
197196
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
198197

199198
visibility => { cdata.get_visibility(def_id.index) }
@@ -473,6 +472,17 @@ impl CStore {
473472
) -> Span {
474473
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
475474
}
475+
476+
pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> Vec<DefId> {
477+
self.get_crate_data(cnum).get_traits().collect()
478+
}
479+
480+
pub fn trait_impls_in_crate_untracked(
481+
&self,
482+
cnum: CrateNum,
483+
) -> Vec<(DefId, Option<SimplifiedType>)> {
484+
self.get_crate_data(cnum).get_trait_impls().collect()
485+
}
476486
}
477487

478488
impl CrateStore for CStore {

compiler/rustc_middle/src/query/mod.rs

-7
Original file line numberDiff line numberDiff line change
@@ -1416,13 +1416,6 @@ rustc_queries! {
14161416
separate_provide_extern
14171417
}
14181418

1419-
/// Given a crate, look up all trait impls in that crate.
1420-
/// Return `(impl_id, self_ty)`.
1421-
query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<SimplifiedType>)] {
1422-
desc { "looking up all (?) trait implementations" }
1423-
separate_provide_extern
1424-
}
1425-
14261419
query is_dllimport_foreign_item(def_id: DefId) -> bool {
14271420
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
14281421
}

src/librustdoc/clean/blanket_impl.rs

+101-100
Original file line numberDiff line numberDiff line change
@@ -19,118 +19,119 @@ 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() {
23-
if !self.cx.cache.access_levels.is_public(trait_def_id)
24-
|| self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
25-
{
26-
continue;
27-
}
28-
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
29-
let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id);
30-
for &impl_def_id in trait_impls.blanket_impls() {
31-
trace!(
32-
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
33-
trait_def_id,
34-
impl_def_id
35-
);
36-
let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap();
37-
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
38-
let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| {
39-
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
40-
let ty = ty.subst(infcx.tcx, substs);
41-
let param_env = param_env.subst(infcx.tcx, substs);
22+
self.cx.with_all_traits(|cx, all_traits| {
23+
for &trait_def_id in all_traits {
24+
if !cx.cache.access_levels.is_public(trait_def_id)
25+
|| cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
26+
{
27+
continue;
28+
}
29+
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
30+
let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
31+
for &impl_def_id in trait_impls.blanket_impls() {
32+
trace!(
33+
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
34+
trait_def_id,
35+
impl_def_id
36+
);
37+
let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
38+
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
39+
let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
40+
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
41+
let ty = ty.subst(infcx.tcx, substs);
42+
let param_env = param_env.subst(infcx.tcx, substs);
4243

43-
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
44-
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
44+
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
45+
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
4546

46-
// Require the type the impl is implemented on to match
47-
// our type, and ignore the impl if there was a mismatch.
48-
let cause = traits::ObligationCause::dummy();
49-
let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
50-
if let Ok(InferOk { value: (), obligations }) = eq_result {
51-
// FIXME(eddyb) ignoring `obligations` might cause false positives.
52-
drop(obligations);
47+
// Require the type the impl is implemented on to match
48+
// our type, and ignore the impl if there was a mismatch.
49+
let cause = traits::ObligationCause::dummy();
50+
let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
51+
if let Ok(InferOk { value: (), obligations }) = eq_result {
52+
// FIXME(eddyb) ignoring `obligations` might cause false positives.
53+
drop(obligations);
5354

54-
trace!(
55-
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
56-
param_env,
57-
trait_ref,
58-
ty
59-
);
60-
let predicates = self
61-
.cx
62-
.tcx
63-
.predicates_of(impl_def_id)
64-
.instantiate(self.cx.tcx, impl_substs)
65-
.predicates
66-
.into_iter()
67-
.chain(Some(
68-
ty::Binder::dummy(trait_ref)
69-
.to_poly_trait_predicate()
70-
.map_bound(ty::PredicateKind::Trait)
71-
.to_predicate(infcx.tcx),
72-
));
73-
for predicate in predicates {
74-
debug!("testing predicate {:?}", predicate);
75-
let obligation = traits::Obligation::new(
76-
traits::ObligationCause::dummy(),
55+
trace!(
56+
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
7757
param_env,
78-
predicate,
58+
trait_ref,
59+
ty
7960
);
80-
match infcx.evaluate_obligation(&obligation) {
81-
Ok(eval_result) if eval_result.may_apply() => {}
82-
Err(traits::OverflowError::Canonical) => {}
83-
Err(traits::OverflowError::ErrorReporting) => {}
84-
_ => {
85-
return false;
61+
let predicates = cx
62+
.tcx
63+
.predicates_of(impl_def_id)
64+
.instantiate(cx.tcx, impl_substs)
65+
.predicates
66+
.into_iter()
67+
.chain(Some(
68+
ty::Binder::dummy(trait_ref)
69+
.to_poly_trait_predicate()
70+
.map_bound(ty::PredicateKind::Trait)
71+
.to_predicate(infcx.tcx),
72+
));
73+
for predicate in predicates {
74+
debug!("testing predicate {:?}", predicate);
75+
let obligation = traits::Obligation::new(
76+
traits::ObligationCause::dummy(),
77+
param_env,
78+
predicate,
79+
);
80+
match infcx.evaluate_obligation(&obligation) {
81+
Ok(eval_result) if eval_result.may_apply() => {}
82+
Err(traits::OverflowError::Canonical) => {}
83+
Err(traits::OverflowError::ErrorReporting) => {}
84+
_ => {
85+
return false;
86+
}
8687
}
8788
}
89+
true
90+
} else {
91+
false
8892
}
89-
true
90-
} else {
91-
false
93+
});
94+
debug!(
95+
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
96+
may_apply, trait_ref, ty
97+
);
98+
if !may_apply {
99+
continue;
92100
}
93-
});
94-
debug!(
95-
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
96-
may_apply, trait_ref, ty
97-
);
98-
if !may_apply {
99-
continue;
100-
}
101101

102-
self.cx.generated_synthetics.insert((ty, trait_def_id));
102+
cx.generated_synthetics.insert((ty, trait_def_id));
103103

104-
impls.push(Item {
105-
name: None,
106-
attrs: Default::default(),
107-
visibility: Inherited,
108-
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
109-
kind: box ImplItem(Impl {
110-
unsafety: hir::Unsafety::Normal,
111-
generics: clean_ty_generics(
112-
self.cx,
113-
self.cx.tcx.generics_of(impl_def_id),
114-
self.cx.tcx.explicit_predicates_of(impl_def_id),
115-
),
116-
// FIXME(eddyb) compute both `trait_` and `for_` from
117-
// the post-inference `trait_ref`, as it's more accurate.
118-
trait_: Some(trait_ref.clean(self.cx)),
119-
for_: ty.clean(self.cx),
120-
items: self
121-
.cx
122-
.tcx
123-
.associated_items(impl_def_id)
124-
.in_definition_order()
125-
.map(|x| x.clean(self.cx))
126-
.collect::<Vec<_>>(),
127-
polarity: ty::ImplPolarity::Positive,
128-
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
129-
}),
130-
cfg: None,
131-
});
104+
impls.push(Item {
105+
name: None,
106+
attrs: Default::default(),
107+
visibility: Inherited,
108+
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
109+
kind: box ImplItem(Impl {
110+
unsafety: hir::Unsafety::Normal,
111+
generics: clean_ty_generics(
112+
cx,
113+
cx.tcx.generics_of(impl_def_id),
114+
cx.tcx.explicit_predicates_of(impl_def_id),
115+
),
116+
// FIXME(eddyb) compute both `trait_` and `for_` from
117+
// the post-inference `trait_ref`, as it's more accurate.
118+
trait_: Some(trait_ref.clean(cx)),
119+
for_: ty.clean(cx),
120+
items: cx
121+
.tcx
122+
.associated_items(impl_def_id)
123+
.in_definition_order()
124+
.map(|x| x.clean(cx))
125+
.collect::<Vec<_>>(),
126+
polarity: ty::ImplPolarity::Positive,
127+
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
128+
}),
129+
cfg: None,
130+
});
131+
}
132132
}
133-
}
133+
});
134+
134135
impls
135136
}
136137
}

src/librustdoc/clean/inline.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ crate fn build_impls(
291291
attrs: Option<Attrs<'_>>,
292292
ret: &mut Vec<clean::Item>,
293293
) {
294+
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
294295
let tcx = cx.tcx;
295296

296297
// for each implementation of an item represented by `did`, build the clean::Item for that impl
@@ -338,7 +339,7 @@ crate fn build_impl(
338339
return;
339340
}
340341

341-
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
342+
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
342343

343344
let tcx = cx.tcx;
344345
let associated_trait = tcx.impl_trait_ref(did);

src/librustdoc/clean/utils.rs

+1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret:
179179
};
180180

181181
if let Some(prim) = target.primitive_type() {
182+
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
182183
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
183184
inline::build_impl(cx, None, did, None, ret);
184185
}

0 commit comments

Comments
 (0)