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:
parent
e48a759f51
commit
f4c183b742
@ -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
|
||||
|
73
src/librustc/traits/trans/mod.rs
Normal file
73
src/librustc/traits/trans/mod.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user