move the trans trait caches into tcx

Arguably these could become custom queries, but I chose not to do that
because the relationship of queries and trait system is not yet fleshed
out enough. For now it seems fine to have them be `DepTrackingMap` using
the memoize pattern.
This commit is contained in:
Niko Matsakis 2017-04-17 12:35:53 -04:00
parent e48a759f51
commit f4c183b742
5 changed files with 89 additions and 78 deletions

View File

@ -55,6 +55,7 @@ mod object_safety;
mod select;
mod specialize;
mod structural_impls;
pub mod trans;
mod util;
/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for

View File

@ -0,0 +1,73 @@
use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
use hir::def_id::DefId;
use std::cell::RefCell;
use std::marker::PhantomData;
use traits::Vtable;
use ty::{self, Ty};
/// Specializes caches used in trans -- in particular, they assume all
/// types are fully monomorphized and that free regions can be erased.
pub struct TransTraitCaches<'tcx> {
pub trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
pub project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
}
impl<'tcx> TransTraitCaches<'tcx> {
pub fn new(graph: DepGraph) -> Self {
TransTraitCaches {
trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())),
project_cache: RefCell::new(DepTrackingMap::new(graph)),
}
}
}
// Implement DepTrackingMapConfig for `trait_cache`
pub struct TraitSelectionCache<'tcx> {
data: PhantomData<&'tcx ()>
}
impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
type Key = ty::PolyTraitRef<'tcx>;
type Value = Vtable<'tcx, ()>;
fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
key.to_poly_trait_predicate().dep_node()
}
}
// # Global Cache
pub struct ProjectionCache<'gcx> {
data: PhantomData<&'gcx ()>
}
impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
type Key = Ty<'gcx>;
type Value = Ty<'gcx>;
fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
// Ideally, we'd just put `key` into the dep-node, but we
// can't put full types in there. So just collect up all the
// def-ids of structs/enums as well as any traits that we
// project out of. It doesn't matter so much what we do here,
// except that if we are too coarse, we'll create overly
// coarse edges between impls and the trans. For example, if
// we just used the def-id of things we are projecting out of,
// then the key for `<Foo as SomeTrait>::T` and `<Bar as
// SomeTrait>::T` would both share a dep-node
// (`TraitSelect(SomeTrait)`), and hence the impls for both
// `Foo` and `Bar` would be considered inputs. So a change to
// `Bar` would affect things that just normalized `Foo`.
// Anyway, this heuristic is not ideal, but better than
// nothing.
let def_ids: Vec<DefId> =
key.walk()
.filter_map(|t| match t.sty {
ty::TyAdt(adt_def, _) => Some(adt_def.did),
ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
_ => None,
})
.collect();
DepNode::ProjectionCache { def_ids: def_ids }
}
}

View File

@ -407,6 +407,8 @@ pub struct GlobalCtxt<'tcx> {
pub specializes_cache: RefCell<traits::SpecializesCache>,
pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
pub dep_graph: DepGraph,
/// Common types, pre-interned for your convenience.
@ -689,6 +691,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
providers[LOCAL_CRATE] = local_providers;
tls::enter_global(GlobalCtxt {
sess: s,
trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
specializes_cache: RefCell::new(traits::SpecializesCache::new()),
global_arenas: arenas,
global_interners: interners,

View File

@ -10,7 +10,7 @@
use llvm;
use llvm::{ContextRef, ModuleRef, ValueRef};
use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig};
use rustc::dep_graph::{DepGraph, DepGraphSafe};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::traits;
@ -34,7 +34,6 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::ptr;
use std::iter;
use std::str;
@ -84,9 +83,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
check_overflow: bool,
use_dll_storage_attrs: bool,
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
}
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@ -171,56 +167,6 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> {
symbol_cache: &'a SymbolCache<'a, 'tcx>,
}
// Implement DepTrackingMapConfig for `trait_cache`
pub struct TraitSelectionCache<'tcx> {
data: PhantomData<&'tcx ()>
}
impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
type Key = ty::PolyTraitRef<'tcx>;
type Value = traits::Vtable<'tcx, ()>;
fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
key.to_poly_trait_predicate().dep_node()
}
}
// # Global Cache
pub struct ProjectionCache<'gcx> {
data: PhantomData<&'gcx ()>
}
impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
type Key = Ty<'gcx>;
type Value = Ty<'gcx>;
fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
// Ideally, we'd just put `key` into the dep-node, but we
// can't put full types in there. So just collect up all the
// def-ids of structs/enums as well as any traits that we
// project out of. It doesn't matter so much what we do here,
// except that if we are too coarse, we'll create overly
// coarse edges between impls and the trans. For example, if
// we just used the def-id of things we are projecting out of,
// then the key for `<Foo as SomeTrait>::T` and `<Bar as
// SomeTrait>::T` would both share a dep-node
// (`TraitSelect(SomeTrait)`), and hence the impls for both
// `Foo` and `Bar` would be considered inputs. So a change to
// `Bar` would affect things that just normalized `Foo`.
// Anyway, this heuristic is not ideal, but better than
// nothing.
let def_ids: Vec<DefId> =
key.walk()
.filter_map(|t| match t.sty {
ty::TyAdt(adt_def, _) => Some(adt_def.did),
ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
_ => None,
})
.collect();
DepNode::ProjectionCache { def_ids: def_ids }
}
}
/// A CrateContext value binds together one LocalCrateContext with the
/// SharedCrateContext. It exists as a convenience wrapper, so we don't have to
/// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans.
@ -382,8 +328,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
tcx: tcx,
check_overflow: check_overflow,
use_dll_storage_attrs: use_dll_storage_attrs,
trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
}
}
@ -403,14 +347,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
&self.exported_symbols
}
pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
&self.trait_cache
}
pub fn project_cache(&self) -> &RefCell<DepTrackingMap<ProjectionCache<'tcx>>> {
&self.project_cache
}
pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.tcx
}

View File

@ -117,7 +117,7 @@ fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
// Remove any references to regions; this helps improve caching.
let trait_ref = tcx.erase_regions(&trait_ref);
scx.trait_cache().memoize(trait_ref, || {
tcx.trans_trait_caches.trait_cache.memoize(trait_ref, || {
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
trait_ref, trait_ref.def_id());
@ -307,7 +307,7 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>,
debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
let substituted = value.subst(tcx, param_substs);
let substituted = scx.tcx().erase_regions(&substituted);
AssociatedTypeNormalizer::new(scx).fold(&substituted)
AssociatedTypeNormalizer::new(tcx).fold(&substituted)
}
/// Returns the normalized type of a struct field
@ -319,15 +319,13 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.normalize_associated_type(&f.ty(tcx, param_substs))
}
struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> {
shared: &'a SharedCrateContext<'b, 'gcx>,
struct AssociatedTypeNormalizer<'a, 'gcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'gcx>,
}
impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> {
fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self {
AssociatedTypeNormalizer {
shared: shared,
}
impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self {
AssociatedTypeNormalizer { tcx }
}
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
@ -339,18 +337,18 @@ impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> {
}
}
impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> {
impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
self.shared.tcx()
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projection_types() {
ty
} else {
self.shared.project_cache().memoize(ty, || {
self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
debug!("AssociatedTypeNormalizer: ty={:?}", ty);
self.shared.tcx().normalize_associated_type(&ty)
self.tcx.normalize_associated_type(&ty)
})
}
}