Skip to content

Commit

Permalink
rustdoc: Introduce a resolver cache for sharing data between early do…
Browse files Browse the repository at this point in the history
…c link resolution and later passes
  • Loading branch information
petrochenkov committed Jan 7, 2022
1 parent e012a19 commit 5acd1f9
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 259 deletions.
14 changes: 12 additions & 2 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
Expand Down Expand Up @@ -192,8 +193,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
extra_filename => { cdata.root.extra_filename.clone() }

traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }

implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }

visibility => { cdata.get_visibility(def_id.index) }
Expand Down Expand Up @@ -473,6 +472,17 @@ impl CStore {
) -> Span {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}

pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> Vec<DefId> {
self.get_crate_data(cnum).get_traits().collect()
}

pub fn trait_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> Vec<(DefId, Option<SimplifiedType>)> {
self.get_crate_data(cnum).get_trait_impls().collect()
}
}

impl CrateStore for CStore {
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1416,13 +1416,6 @@ rustc_queries! {
separate_provide_extern
}

/// Given a crate, look up all trait impls in that crate.
/// Return `(impl_id, self_ty)`.
query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }
separate_provide_extern
}

query is_dllimport_foreign_item(def_id: DefId) -> bool {
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
}
Expand Down
201 changes: 101 additions & 100 deletions src/librustdoc/clean/blanket_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,118 +19,119 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {

trace!("get_blanket_impls({:?})", ty);
let mut impls = Vec::new();
for trait_def_id in self.cx.tcx.all_traits() {
if !self.cx.cache.access_levels.is_public(trait_def_id)
|| self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
{
continue;
}
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id);
for &impl_def_id in trait_impls.blanket_impls() {
trace!(
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
trait_def_id,
impl_def_id
);
let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap();
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| {
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
let ty = ty.subst(infcx.tcx, substs);
let param_env = param_env.subst(infcx.tcx, substs);
self.cx.with_all_traits(|cx, all_traits| {
for &trait_def_id in all_traits {
if !cx.cache.access_levels.is_public(trait_def_id)
|| cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
{
continue;
}
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
for &impl_def_id in trait_impls.blanket_impls() {
trace!(
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
trait_def_id,
impl_def_id
);
let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
let ty = ty.subst(infcx.tcx, substs);
let param_env = param_env.subst(infcx.tcx, substs);

let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);

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

trace!(
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
param_env,
trait_ref,
ty
);
let predicates = self
.cx
.tcx
.predicates_of(impl_def_id)
.instantiate(self.cx.tcx, impl_substs)
.predicates
.into_iter()
.chain(Some(
ty::Binder::dummy(trait_ref)
.to_poly_trait_predicate()
.map_bound(ty::PredicateKind::Trait)
.to_predicate(infcx.tcx),
));
for predicate in predicates {
debug!("testing predicate {:?}", predicate);
let obligation = traits::Obligation::new(
traits::ObligationCause::dummy(),
trace!(
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
param_env,
predicate,
trait_ref,
ty
);
match infcx.evaluate_obligation(&obligation) {
Ok(eval_result) if eval_result.may_apply() => {}
Err(traits::OverflowError::Canonical) => {}
Err(traits::OverflowError::ErrorReporting) => {}
_ => {
return false;
let predicates = cx
.tcx
.predicates_of(impl_def_id)
.instantiate(cx.tcx, impl_substs)
.predicates
.into_iter()
.chain(Some(
ty::Binder::dummy(trait_ref)
.to_poly_trait_predicate()
.map_bound(ty::PredicateKind::Trait)
.to_predicate(infcx.tcx),
));
for predicate in predicates {
debug!("testing predicate {:?}", predicate);
let obligation = traits::Obligation::new(
traits::ObligationCause::dummy(),
param_env,
predicate,
);
match infcx.evaluate_obligation(&obligation) {
Ok(eval_result) if eval_result.may_apply() => {}
Err(traits::OverflowError::Canonical) => {}
Err(traits::OverflowError::ErrorReporting) => {}
_ => {
return false;
}
}
}
true
} else {
false
}
true
} else {
false
});
debug!(
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
may_apply, trait_ref, ty
);
if !may_apply {
continue;
}
});
debug!(
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
may_apply, trait_ref, ty
);
if !may_apply {
continue;
}

self.cx.generated_synthetics.insert((ty, trait_def_id));
cx.generated_synthetics.insert((ty, trait_def_id));

impls.push(Item {
name: None,
attrs: Default::default(),
visibility: Inherited,
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: clean_ty_generics(
self.cx,
self.cx.tcx.generics_of(impl_def_id),
self.cx.tcx.explicit_predicates_of(impl_def_id),
),
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(self.cx)),
for_: ty.clean(self.cx),
items: self
.cx
.tcx
.associated_items(impl_def_id)
.in_definition_order()
.map(|x| x.clean(self.cx))
.collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
}),
cfg: None,
});
impls.push(Item {
name: None,
attrs: Default::default(),
visibility: Inherited,
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: clean_ty_generics(
cx,
cx.tcx.generics_of(impl_def_id),
cx.tcx.explicit_predicates_of(impl_def_id),
),
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(cx)),
for_: ty.clean(cx),
items: cx
.tcx
.associated_items(impl_def_id)
.in_definition_order()
.map(|x| x.clean(cx))
.collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
}),
cfg: None,
});
}
}
}
});

impls
}
}
3 changes: 2 additions & 1 deletion src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ crate fn build_impls(
attrs: Option<Attrs<'_>>,
ret: &mut Vec<clean::Item>,
) {
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
let tcx = cx.tcx;

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

let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");

let tcx = cx.tcx;
let associated_trait = tcx.impl_trait_ref(did);
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret:
};

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

0 comments on commit 5acd1f9

Please sign in to comment.