Refactor compiler to make use of dep-tracking-maps. Also, in cases where
we were using interior mutability (RefCells, TyIvar), add some reads/writes.
This commit is contained in:
parent
5d9dd7cf33
commit
d48f48f61f
10 changed files with 511 additions and 316 deletions
|
@ -13,6 +13,7 @@ use std::cell::RefCell;
|
|||
use std::ops::Index;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use util::common::MemoizationMap;
|
||||
|
||||
use super::{DepNode, DepGraph};
|
||||
|
||||
|
@ -70,6 +71,61 @@ impl<M: DepTrackingMapId> DepTrackingMap<M> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<M: DepTrackingMapId> MemoizationMap for RefCell<DepTrackingMap<M>> {
|
||||
type Key = M::Key;
|
||||
type Value = M::Value;
|
||||
|
||||
/// Memoizes an entry in the dep-tracking-map. If the entry is not
|
||||
/// already present, then `op` will be executed to compute its value.
|
||||
/// The resulting dependency graph looks like this:
|
||||
///
|
||||
/// [op] -> Map(key) -> CurrentTask
|
||||
///
|
||||
/// Here, `[op]` represents whatever nodes `op` reads in the
|
||||
/// course of execution; `Map(key)` represents the node for this
|
||||
/// map; and `CurrentTask` represents the current task when
|
||||
/// `memoize` is invoked.
|
||||
///
|
||||
/// **Important:* when `op` is invoked, the current task will be
|
||||
/// switched to `Map(key)`. Therefore, if `op` makes use of any
|
||||
/// HIR nodes or shared state accessed through its closure
|
||||
/// environment, it must explicitly read that state. As an
|
||||
/// example, see `type_scheme_of_item` in `collect`, which looks
|
||||
/// something like this:
|
||||
///
|
||||
/// ```
|
||||
/// fn type_scheme_of_item(..., item: &hir::Item) -> ty::TypeScheme<'tcx> {
|
||||
/// let item_def_id = ccx.tcx.map.local_def_id(it.id);
|
||||
/// ccx.tcx.tcache.memoized(item_def_id, || {
|
||||
/// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
|
||||
/// compute_type_scheme_of_item(ccx, item)
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The key is the line marked `(*)`: the closure implicitly
|
||||
/// accesses the body of the item `item`, so we register a read
|
||||
/// from `Hir(item_def_id)`.
|
||||
fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
|
||||
where OP: FnOnce() -> M::Value
|
||||
{
|
||||
let graph;
|
||||
{
|
||||
let this = self.borrow();
|
||||
if let Some(result) = this.map.get(&key) {
|
||||
this.read(&key);
|
||||
return result.clone();
|
||||
}
|
||||
graph = this.graph.clone();
|
||||
}
|
||||
|
||||
let _task = graph.in_task(M::to_dep_node(&key));
|
||||
let result = op();
|
||||
self.borrow_mut().map.insert(key, result.clone());
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'k, M: DepTrackingMapId> Index<&'k M::Key> for DepTrackingMap<M> {
|
||||
type Output = M::Value;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use middle::def_id::{DefId};
|
||||
use middle::ty::{self, Ty};
|
||||
use util::common::{memoized};
|
||||
use util::common::MemoizationMap;
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
use std::fmt;
|
||||
|
@ -141,9 +141,7 @@ impl fmt::Debug for TypeContents {
|
|||
|
||||
impl<'tcx> ty::TyS<'tcx> {
|
||||
pub fn type_contents(&'tcx self, cx: &ty::ctxt<'tcx>) -> TypeContents {
|
||||
return memoized(&cx.tc_cache, self, |ty| {
|
||||
tc_ty(cx, ty, &mut FnvHashMap())
|
||||
});
|
||||
return cx.tc_cache.memoize(self, || tc_ty(cx, self, &mut FnvHashMap()));
|
||||
|
||||
fn tc_ty<'tcx>(cx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
|
@ -30,10 +30,12 @@ use middle::traits;
|
|||
use middle::ty::{self, TraitRef, Ty, TypeAndMut};
|
||||
use middle::ty::{TyS, TypeVariants};
|
||||
use middle::ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region};
|
||||
use middle::ty::{FreevarMap, GenericPredicates};
|
||||
use middle::ty::{FreevarMap};
|
||||
use middle::ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
|
||||
use middle::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
|
||||
use middle::ty::TypeVariants::*;
|
||||
use middle::ty::maps;
|
||||
use util::common::MemoizationMap;
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
|
@ -248,21 +250,23 @@ pub struct ctxt<'tcx> {
|
|||
pub tables: RefCell<Tables<'tcx>>,
|
||||
|
||||
/// Maps from a trait item to the trait item "descriptor"
|
||||
pub impl_or_trait_items: RefCell<DefIdMap<ty::ImplOrTraitItem<'tcx>>>,
|
||||
pub impl_or_trait_items: RefCell<DepTrackingMap<maps::ImplOrTraitItems<'tcx>>>,
|
||||
|
||||
/// Maps from a trait def-id to a list of the def-ids of its trait items
|
||||
pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItemId>>>>,
|
||||
pub trait_item_def_ids: RefCell<DepTrackingMap<maps::TraitItemDefIds<'tcx>>>,
|
||||
|
||||
/// A cache for the trait_items() routine
|
||||
pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
|
||||
/// A cache for the trait_items() routine; note that the routine
|
||||
/// itself pushes the `TraitItems` dependency node. This cache is
|
||||
/// "encapsulated" and thus does not need to be itself tracked.
|
||||
trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
|
||||
|
||||
pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
|
||||
pub trait_defs: RefCell<DefIdMap<&'tcx ty::TraitDef<'tcx>>>,
|
||||
pub adt_defs: RefCell<DefIdMap<ty::AdtDefMaster<'tcx>>>,
|
||||
pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
|
||||
pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
|
||||
pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
|
||||
|
||||
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
|
||||
/// associated predicates.
|
||||
pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
|
||||
pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
|
||||
|
||||
/// Maps from the def-id of a trait to the list of
|
||||
/// super-predicates. This is a subset of the full list of
|
||||
|
@ -270,21 +274,40 @@ pub struct ctxt<'tcx> {
|
|||
/// evaluate them even during type conversion, often before the
|
||||
/// full predicates are available (note that supertraits have
|
||||
/// additional acyclicity requirements).
|
||||
pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
|
||||
pub super_predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
|
||||
|
||||
pub map: ast_map::Map<'tcx>,
|
||||
|
||||
// Records the free variables refrenced by every closure
|
||||
// expression. Do not track deps for this, just recompute it from
|
||||
// scratch every time.
|
||||
pub freevars: RefCell<FreevarMap>,
|
||||
pub tcache: RefCell<DefIdMap<ty::TypeScheme<'tcx>>>,
|
||||
|
||||
// Records the type of every item.
|
||||
pub tcache: RefCell<DepTrackingMap<maps::Tcache<'tcx>>>,
|
||||
|
||||
// Internal cache for metadata decoding. No need to track deps on this.
|
||||
pub rcache: RefCell<FnvHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
|
||||
|
||||
// Cache for the type-contents routine. FIXME -- track deps?
|
||||
pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
|
||||
|
||||
// Cache for various types within a method body and so forth.
|
||||
//
|
||||
// FIXME this should be made local to typeck, but it is currently used by one lint
|
||||
pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
|
||||
|
||||
// FIXME no dep tracking, but we should be able to remove this
|
||||
pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
|
||||
|
||||
// FIXME dep tracking -- should be harmless enough
|
||||
pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
|
||||
|
||||
pub lang_items: middle::lang_items::LanguageItems,
|
||||
|
||||
/// Maps from def-id of a type or region parameter to its
|
||||
/// (inferred) variance.
|
||||
pub item_variance_map: RefCell<DefIdMap<Rc<ty::ItemVariances>>>,
|
||||
pub item_variance_map: RefCell<DepTrackingMap<maps::ItemVariances<'tcx>>>,
|
||||
|
||||
/// True if the variance has been computed yet; false otherwise.
|
||||
pub variance_computed: Cell<bool>,
|
||||
|
@ -292,13 +315,13 @@ pub struct ctxt<'tcx> {
|
|||
/// Maps a DefId of a type to a list of its inherent impls.
|
||||
/// Contains implementations of methods that are inherent to a type.
|
||||
/// Methods in these implementations don't need to be exported.
|
||||
pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
|
||||
pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
|
||||
|
||||
/// Maps a DefId of an impl to a list of its items.
|
||||
/// Note that this contains all of the impls that we know about,
|
||||
/// including ones in other crates. It's not clear that this is the best
|
||||
/// way to do it.
|
||||
pub impl_items: RefCell<DefIdMap<Vec<ty::ImplOrTraitItemId>>>,
|
||||
pub impl_items: RefCell<DepTrackingMap<maps::ImplItems<'tcx>>>,
|
||||
|
||||
/// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
|
||||
/// present in this set can be warned about.
|
||||
|
@ -312,6 +335,7 @@ pub struct ctxt<'tcx> {
|
|||
/// The set of external nominal types whose implementations have been read.
|
||||
/// This is used for lazy resolution of methods.
|
||||
pub populated_external_types: RefCell<DefIdSet>,
|
||||
|
||||
/// The set of external primitive types whose implementations have been read.
|
||||
/// FIXME(arielb1): why is this separate from populated_external_types?
|
||||
pub populated_external_primitive_impls: RefCell<DefIdSet>,
|
||||
|
@ -347,7 +371,9 @@ pub struct ctxt<'tcx> {
|
|||
pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
|
||||
|
||||
/// Caches the representation hints for struct definitions.
|
||||
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
|
||||
///
|
||||
/// This is encapsulated by the `ReprHints` task and hence is not tracked.
|
||||
repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
|
||||
|
||||
/// Maps Expr NodeId's to their constant qualification.
|
||||
pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
|
||||
|
@ -499,31 +525,31 @@ impl<'tcx> ctxt<'tcx> {
|
|||
named_region_map: named_region_map,
|
||||
region_maps: region_maps,
|
||||
free_region_maps: RefCell::new(FnvHashMap()),
|
||||
item_variance_map: RefCell::new(DefIdMap()),
|
||||
item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
variance_computed: Cell::new(false),
|
||||
sess: s,
|
||||
def_map: def_map,
|
||||
tables: RefCell::new(Tables::empty()),
|
||||
impl_trait_refs: RefCell::new(DefIdMap()),
|
||||
trait_defs: RefCell::new(DefIdMap()),
|
||||
adt_defs: RefCell::new(DefIdMap()),
|
||||
predicates: RefCell::new(DefIdMap()),
|
||||
super_predicates: RefCell::new(DefIdMap()),
|
||||
impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
|
||||
map: map,
|
||||
freevars: RefCell::new(freevars),
|
||||
tcache: RefCell::new(DefIdMap()),
|
||||
tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
rcache: RefCell::new(FnvHashMap()),
|
||||
tc_cache: RefCell::new(FnvHashMap()),
|
||||
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
||||
impl_or_trait_items: RefCell::new(DefIdMap()),
|
||||
trait_item_def_ids: RefCell::new(DefIdMap()),
|
||||
impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
trait_items_cache: RefCell::new(DefIdMap()),
|
||||
ty_param_defs: RefCell::new(NodeMap()),
|
||||
normalized_cache: RefCell::new(FnvHashMap()),
|
||||
lang_items: lang_items,
|
||||
inherent_impls: RefCell::new(DefIdMap()),
|
||||
impl_items: RefCell::new(DefIdMap()),
|
||||
inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
used_unsafe: RefCell::new(NodeSet()),
|
||||
used_mut_nodes: RefCell::new(NodeSet()),
|
||||
populated_external_types: RefCell::new(DefIdSet()),
|
||||
|
@ -1004,4 +1030,38 @@ impl<'tcx> ctxt<'tcx> {
|
|||
pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
|
||||
self.mk_param(def.space, def.index, def.name)
|
||||
}
|
||||
|
||||
pub fn trait_items(&self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> {
|
||||
// since this is cached, pushing a dep-node for the
|
||||
// computation yields the correct dependencies.
|
||||
let _task = self.dep_graph.in_task(DepNode::TraitItems(trait_did));
|
||||
|
||||
let mut trait_items = self.trait_items_cache.borrow_mut();
|
||||
match trait_items.get(&trait_did).cloned() {
|
||||
Some(trait_items) => trait_items,
|
||||
None => {
|
||||
let def_ids = self.trait_item_def_ids(trait_did);
|
||||
let items: Rc<Vec<_>> =
|
||||
Rc::new(def_ids.iter()
|
||||
.map(|d| self.impl_or_trait_item(d.def_id()))
|
||||
.collect());
|
||||
trait_items.insert(trait_did, items.clone());
|
||||
items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the representation annotation for a struct definition.
|
||||
pub fn lookup_repr_hints(&self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
|
||||
let _task = self.dep_graph.in_task(DepNode::ReprHints(did));
|
||||
self.repr_hint_cache.memoize(did, || {
|
||||
Rc::new(if did.is_local() {
|
||||
self.get_attrs(did).iter().flat_map(|meta| {
|
||||
attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
|
||||
}).collect()
|
||||
} else {
|
||||
self.sess.cstore.repr_attrs(did)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use dep_graph::DepNode;
|
||||
use middle::ty::{Ty, TyS};
|
||||
use middle::ty::tls;
|
||||
|
||||
use rustc_data_structures::ivar;
|
||||
|
||||
|
@ -27,6 +29,10 @@ use core::nonzero::NonZero;
|
|||
/// (B) no aliases to this value with a 'tcx longer than this
|
||||
/// value's 'lt exist
|
||||
///
|
||||
/// Dependency tracking: each ivar does not know what node in the
|
||||
/// dependency graph it is associated with, so when you get/fulfill
|
||||
/// you must supply a `DepNode` id. This should always be the same id!
|
||||
///
|
||||
/// NonZero is used rather than Unique because Unique isn't Copy.
|
||||
pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
|
||||
PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
|
||||
|
@ -40,19 +46,28 @@ impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self) -> Option<Ty<'tcx>> {
|
||||
pub fn get(&self, dep_node: DepNode) -> Option<Ty<'tcx>> {
|
||||
tls::with(|tcx| tcx.dep_graph.read(dep_node));
|
||||
self.untracked_get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn untracked_get(&self) -> Option<Ty<'tcx>> {
|
||||
match self.0.get() {
|
||||
None => None,
|
||||
// valid because of invariant (A)
|
||||
Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unwrap(&self) -> Ty<'tcx> {
|
||||
self.get().unwrap()
|
||||
pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> {
|
||||
self.get(dep_node).unwrap()
|
||||
}
|
||||
|
||||
pub fn fulfill(&self, value: Ty<'lt>) {
|
||||
pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) {
|
||||
tls::with(|tcx| tcx.dep_graph.write(dep_node));
|
||||
|
||||
// Invariant (A) is fulfilled, because by (B), every alias
|
||||
// of this has a 'tcx longer than 'lt.
|
||||
let value: *const TyS<'lt> = value;
|
||||
|
@ -64,7 +79,7 @@ impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
|
|||
|
||||
impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.get() {
|
||||
match self.untracked_get() {
|
||||
Some(val) => write!(f, "TyIVar({:?})", val),
|
||||
None => f.write_str("TyIVar(<unfulfilled>)")
|
||||
}
|
||||
|
|
41
src/librustc/middle/ty/maps.rs
Normal file
41
src/librustc/middle/ty/maps.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use dep_graph::{DepNode, DepTrackingMapId};
|
||||
use middle::def_id::DefId;
|
||||
use middle::ty;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
|
||||
macro_rules! dep_map_ty {
|
||||
($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
|
||||
pub struct $ty_name<'tcx> {
|
||||
data: PhantomData<&'tcx ()>
|
||||
}
|
||||
|
||||
impl<'tcx> DepTrackingMapId for $ty_name<'tcx> {
|
||||
type Key = $key;
|
||||
type Value = $value;
|
||||
fn to_dep_node(key: &$key) -> DepNode { DepNode::$node_name(*key) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> }
|
||||
dep_map_ty! { Tcache: ItemSignature(DefId) -> ty::TypeScheme<'tcx> }
|
||||
dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
|
||||
dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
|
||||
dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc<Vec<ty::ImplOrTraitItemId>> }
|
||||
dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
|
||||
dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> }
|
||||
dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> }
|
||||
dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<ty::ItemVariances> }
|
||||
dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc<Vec<DefId>> }
|
||||
dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
|
|
@ -18,6 +18,7 @@ pub use self::ImplOrTraitItem::*;
|
|||
pub use self::IntVarValue::*;
|
||||
pub use self::LvaluePreference::*;
|
||||
|
||||
use dep_graph::{self, DepNode};
|
||||
use front::map as ast_map;
|
||||
use front::map::LinkedPath;
|
||||
use middle;
|
||||
|
@ -31,13 +32,13 @@ use middle::traits;
|
|||
use middle::ty;
|
||||
use middle::ty::fold::TypeFolder;
|
||||
use middle::ty::walk::TypeWalker;
|
||||
use util::common::memoized;
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap};
|
||||
use util::common::MemoizationMap;
|
||||
use util::nodemap::{NodeMap, NodeSet};
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
use serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::Cell;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
|
@ -76,14 +77,18 @@ pub use self::contents::TypeContents;
|
|||
pub use self::context::{ctxt, tls};
|
||||
pub use self::context::{CtxtArenas, Lift, Tables};
|
||||
|
||||
pub use self::trait_def::{TraitDef, TraitFlags};
|
||||
|
||||
pub mod adjustment;
|
||||
pub mod cast;
|
||||
pub mod error;
|
||||
pub mod fast_reject;
|
||||
pub mod fold;
|
||||
pub mod _match;
|
||||
pub mod maps;
|
||||
pub mod outlives;
|
||||
pub mod relate;
|
||||
pub mod trait_def;
|
||||
pub mod walk;
|
||||
pub mod wf;
|
||||
pub mod util;
|
||||
|
@ -1318,161 +1323,6 @@ pub struct TypeScheme<'tcx> {
|
|||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
flags TraitFlags: u32 {
|
||||
const NO_TRAIT_FLAGS = 0,
|
||||
const HAS_DEFAULT_IMPL = 1 << 0,
|
||||
const IS_OBJECT_SAFE = 1 << 1,
|
||||
const OBJECT_SAFETY_VALID = 1 << 2,
|
||||
const IMPLS_VALID = 1 << 3,
|
||||
}
|
||||
}
|
||||
|
||||
/// As `TypeScheme` but for a trait ref.
|
||||
pub struct TraitDef<'tcx> {
|
||||
pub unsafety: hir::Unsafety,
|
||||
|
||||
/// If `true`, then this trait had the `#[rustc_paren_sugar]`
|
||||
/// attribute, indicating that it should be used with `Foo()`
|
||||
/// sugar. This is a temporary thing -- eventually any trait wil
|
||||
/// be usable with the sugar (or without it).
|
||||
pub paren_sugar: bool,
|
||||
|
||||
/// Generic type definitions. Note that `Self` is listed in here
|
||||
/// as having a single bound, the trait itself (e.g., in the trait
|
||||
/// `Eq`, there is a single bound `Self : Eq`). This is so that
|
||||
/// default methods get to assume that the `Self` parameters
|
||||
/// implements the trait.
|
||||
pub generics: Generics<'tcx>,
|
||||
|
||||
pub trait_ref: TraitRef<'tcx>,
|
||||
|
||||
/// A list of the associated types defined in this trait. Useful
|
||||
/// for resolving `X::Foo` type markers.
|
||||
pub associated_type_names: Vec<Name>,
|
||||
|
||||
// Impls of this trait. To allow for quicker lookup, the impls are indexed
|
||||
// by a simplified version of their Self type: impls with a simplifiable
|
||||
// Self are stored in nonblanket_impls keyed by it, while all other impls
|
||||
// are stored in blanket_impls.
|
||||
|
||||
/// Impls of the trait.
|
||||
pub nonblanket_impls: RefCell<
|
||||
FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>
|
||||
>,
|
||||
|
||||
/// Blanket impls associated with the trait.
|
||||
pub blanket_impls: RefCell<Vec<DefId>>,
|
||||
|
||||
/// Various flags
|
||||
pub flags: Cell<TraitFlags>
|
||||
}
|
||||
|
||||
impl<'tcx> TraitDef<'tcx> {
|
||||
// returns None if not yet calculated
|
||||
pub fn object_safety(&self) -> Option<bool> {
|
||||
if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) {
|
||||
Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_object_safety(&self, is_safe: bool) {
|
||||
assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true));
|
||||
self.flags.set(
|
||||
self.flags.get() | if is_safe {
|
||||
TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE
|
||||
} else {
|
||||
TraitFlags::OBJECT_SAFETY_VALID
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping.
|
||||
pub fn record_impl(&self,
|
||||
tcx: &ctxt<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
impl_trait_ref: TraitRef<'tcx>) {
|
||||
debug!("TraitDef::record_impl for {:?}, from {:?}",
|
||||
self, impl_trait_ref);
|
||||
|
||||
// We don't want to borrow_mut after we already populated all impls,
|
||||
// so check if an impl is present with an immutable borrow first.
|
||||
if let Some(sty) = fast_reject::simplify_type(tcx,
|
||||
impl_trait_ref.self_ty(), false) {
|
||||
if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
|
||||
if is.contains(&impl_def_id) {
|
||||
return // duplicate - skip
|
||||
}
|
||||
}
|
||||
|
||||
self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
|
||||
} else {
|
||||
if self.blanket_impls.borrow().contains(&impl_def_id) {
|
||||
return // duplicate - skip
|
||||
}
|
||||
self.blanket_impls.borrow_mut().push(impl_def_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &ctxt<'tcx>, mut f: F) {
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
|
||||
|
||||
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
|
||||
for v in self.nonblanket_impls.borrow().values() {
|
||||
for &impl_def_id in v {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over every impl that could possibly match the
|
||||
/// self-type `self_ty`.
|
||||
pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
|
||||
tcx: &ctxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut f: F)
|
||||
{
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
|
||||
|
||||
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
|
||||
// simplify_type(.., false) basically replaces type parameters and
|
||||
// projections with infer-variables. This is, of course, done on
|
||||
// the impl trait-ref when it is instantiated, but not on the
|
||||
// predicate trait-ref which is passed here.
|
||||
//
|
||||
// for example, if we match `S: Copy` against an impl like
|
||||
// `impl<T:Copy> Copy for Option<T>`, we replace the type variable
|
||||
// in `Option<T>` with an infer variable, to `Option<_>` (this
|
||||
// doesn't actually change fast_reject output), but we don't
|
||||
// replace `S` with anything - this impl of course can't be
|
||||
// selected, and as there are hundreds of similar impls,
|
||||
// considering them would significantly harm performance.
|
||||
if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
|
||||
if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
|
||||
for &impl_def_id in impls {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for v in self.nonblanket_impls.borrow().values() {
|
||||
for &impl_def_id in v {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
flags AdtFlags: u32 {
|
||||
const NO_ADT_FLAGS = 0,
|
||||
|
@ -1514,6 +1364,8 @@ pub struct FieldDefData<'tcx, 'container: 'tcx> {
|
|||
pub vis: hir::Visibility,
|
||||
/// TyIVar is used here to allow for variance (see the doc at
|
||||
/// AdtDefData).
|
||||
///
|
||||
/// Note: direct accesses to `ty` must also add dep edges.
|
||||
ty: ivar::TyIVar<'tcx, 'container>
|
||||
}
|
||||
|
||||
|
@ -1804,11 +1656,11 @@ impl<'tcx, 'container> FieldDefData<'tcx, 'container> {
|
|||
}
|
||||
|
||||
pub fn unsubst_ty(&self) -> Ty<'tcx> {
|
||||
self.ty.unwrap()
|
||||
self.ty.unwrap(DepNode::FieldTy(self.did))
|
||||
}
|
||||
|
||||
pub fn fulfill_ty(&self, ty: Ty<'container>) {
|
||||
self.ty.fulfill(ty);
|
||||
self.ty.fulfill(DepNode::FieldTy(self.did), ty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1931,31 +1783,20 @@ impl LvaluePreference {
|
|||
/// into the map by the `typeck::collect` phase. If the def-id is external,
|
||||
/// then we have to go consult the crate loading code (and cache the result for
|
||||
/// the future).
|
||||
fn lookup_locally_or_in_crate_store<V, F>(descr: &str,
|
||||
fn lookup_locally_or_in_crate_store<M, F>(descr: &str,
|
||||
def_id: DefId,
|
||||
map: &RefCell<DefIdMap<V>>,
|
||||
load_external: F) -> V where
|
||||
V: Clone,
|
||||
F: FnOnce() -> V,
|
||||
map: &M,
|
||||
load_external: F)
|
||||
-> M::Value where
|
||||
M: MemoizationMap<Key=DefId>,
|
||||
F: FnOnce() -> M::Value,
|
||||
{
|
||||
match map.borrow().get(&def_id).cloned() {
|
||||
Some(v) => { return v; }
|
||||
None => { }
|
||||
}
|
||||
|
||||
if def_id.is_local() {
|
||||
panic!("No def'n found for {:?} in tcx.{}", def_id, descr);
|
||||
}
|
||||
let v = load_external();
|
||||
|
||||
// Don't consider this a write from the current task, since we are
|
||||
// loading from another crate. (Note that the current task will
|
||||
// already have registered a read in the call to `get` above.)
|
||||
dep_graph.with_ignore(|| {
|
||||
map.borrow_mut().insert(def_id, v.clone());
|
||||
});
|
||||
|
||||
v
|
||||
map.memoize(def_id, || {
|
||||
if def_id.is_local() {
|
||||
panic!("No def'n found for {:?} in tcx.{}", def_id, descr);
|
||||
}
|
||||
load_external()
|
||||
})
|
||||
}
|
||||
|
||||
impl BorrowKind {
|
||||
|
@ -2231,22 +2072,6 @@ impl<'tcx> ctxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn trait_items(&self, trait_did: DefId) -> Rc<Vec<ImplOrTraitItem<'tcx>>> {
|
||||
let mut trait_items = self.trait_items_cache.borrow_mut();
|
||||
match trait_items.get(&trait_did).cloned() {
|
||||
Some(trait_items) => trait_items,
|
||||
None => {
|
||||
let def_ids = self.trait_item_def_ids(trait_did);
|
||||
let items: Rc<Vec<ImplOrTraitItem>> =
|
||||
Rc::new(def_ids.iter()
|
||||
.map(|d| self.impl_or_trait_item(d.def_id()))
|
||||
.collect());
|
||||
trait_items.insert(trait_did, items.clone());
|
||||
items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_impl_polarity(&self, id: DefId) -> Option<hir::ImplPolarity> {
|
||||
if let Some(id) = self.map.as_local_node_id(id) {
|
||||
match self.map.find(id) {
|
||||
|
@ -2264,7 +2089,7 @@ impl<'tcx> ctxt<'tcx> {
|
|||
}
|
||||
|
||||
pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized {
|
||||
memoized(&self.custom_coerce_unsized_kinds, did, |did: DefId| {
|
||||
self.custom_coerce_unsized_kinds.memoize(did, || {
|
||||
let (kind, src) = if did.krate != LOCAL_CRATE {
|
||||
(self.sess.cstore.custom_coerce_unsized_kind(did), "external")
|
||||
} else {
|
||||
|
@ -2427,19 +2252,6 @@ impl<'tcx> ctxt<'tcx> {
|
|||
|| self.lookup_repr_hints(did).contains(&attr::ReprSimd)
|
||||
}
|
||||
|
||||
/// Obtain the representation annotation for a struct definition.
|
||||
pub fn lookup_repr_hints(&self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
|
||||
memoized(&self.repr_hint_cache, did, |did: DefId| {
|
||||
Rc::new(if did.is_local() {
|
||||
self.get_attrs(did).iter().flat_map(|meta| {
|
||||
attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
|
||||
}).collect()
|
||||
} else {
|
||||
self.sess.cstore.repr_attrs(did)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn item_variances(&self, item_id: DefId) -> Rc<ItemVariances> {
|
||||
lookup_locally_or_in_crate_store(
|
||||
"item_variance_map", item_id, &self.item_variance_map,
|
||||
|
|
226
src/librustc/middle/ty/trait_def.rs
Normal file
226
src/librustc/middle/ty/trait_def.rs
Normal file
|
@ -0,0 +1,226 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use dep_graph::DepNode;
|
||||
use middle::def_id::DefId;
|
||||
use middle::ty;
|
||||
use middle::ty::fast_reject;
|
||||
use middle::ty::Ty;
|
||||
use std::borrow::{Borrow};
|
||||
use std::cell::{Cell, Ref, RefCell};
|
||||
use syntax::ast::Name;
|
||||
use rustc_front::hir;
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
/// As `TypeScheme` but for a trait ref.
|
||||
pub struct TraitDef<'tcx> {
|
||||
pub unsafety: hir::Unsafety,
|
||||
|
||||
/// If `true`, then this trait had the `#[rustc_paren_sugar]`
|
||||
/// attribute, indicating that it should be used with `Foo()`
|
||||
/// sugar. This is a temporary thing -- eventually any trait wil
|
||||
/// be usable with the sugar (or without it).
|
||||
pub paren_sugar: bool,
|
||||
|
||||
/// Generic type definitions. Note that `Self` is listed in here
|
||||
/// as having a single bound, the trait itself (e.g., in the trait
|
||||
/// `Eq`, there is a single bound `Self : Eq`). This is so that
|
||||
/// default methods get to assume that the `Self` parameters
|
||||
/// implements the trait.
|
||||
pub generics: ty::Generics<'tcx>,
|
||||
|
||||
pub trait_ref: ty::TraitRef<'tcx>,
|
||||
|
||||
/// A list of the associated types defined in this trait. Useful
|
||||
/// for resolving `X::Foo` type markers.
|
||||
pub associated_type_names: Vec<Name>,
|
||||
|
||||
// Impls of this trait. To allow for quicker lookup, the impls are indexed
|
||||
// by a simplified version of their Self type: impls with a simplifiable
|
||||
// Self are stored in nonblanket_impls keyed by it, while all other impls
|
||||
// are stored in blanket_impls.
|
||||
//
|
||||
// These lists are tracked by `DepNode::TraitImpls`; we don't use
|
||||
// a DepTrackingMap but instead have the `TraitDef` insert the
|
||||
// required reads/writes.
|
||||
|
||||
/// Impls of the trait.
|
||||
nonblanket_impls: RefCell<
|
||||
FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>
|
||||
>,
|
||||
|
||||
/// Blanket impls associated with the trait.
|
||||
blanket_impls: RefCell<Vec<DefId>>,
|
||||
|
||||
/// Various flags
|
||||
pub flags: Cell<TraitFlags>
|
||||
}
|
||||
|
||||
impl<'tcx> TraitDef<'tcx> {
|
||||
pub fn new(unsafety: hir::Unsafety,
|
||||
paren_sugar: bool,
|
||||
generics: ty::Generics<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
associated_type_names: Vec<Name>)
|
||||
-> TraitDef<'tcx> {
|
||||
TraitDef {
|
||||
paren_sugar: paren_sugar,
|
||||
unsafety: unsafety,
|
||||
generics: generics,
|
||||
trait_ref: trait_ref,
|
||||
associated_type_names: associated_type_names,
|
||||
nonblanket_impls: RefCell::new(FnvHashMap()),
|
||||
blanket_impls: RefCell::new(vec![]),
|
||||
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
self.trait_ref.def_id
|
||||
}
|
||||
|
||||
// returns None if not yet calculated
|
||||
pub fn object_safety(&self) -> Option<bool> {
|
||||
if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) {
|
||||
Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_object_safety(&self, is_safe: bool) {
|
||||
assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true));
|
||||
self.flags.set(
|
||||
self.flags.get() | if is_safe {
|
||||
TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE
|
||||
} else {
|
||||
TraitFlags::OBJECT_SAFETY_VALID
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn write_trait_impls(&self, tcx: &ty::ctxt<'tcx>) {
|
||||
tcx.dep_graph.write(DepNode::TraitImpls(self.trait_ref.def_id));
|
||||
}
|
||||
|
||||
fn read_trait_impls(&self, tcx: &ty::ctxt<'tcx>) {
|
||||
tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id));
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping.
|
||||
pub fn record_impl(&self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>) {
|
||||
debug!("TraitDef::record_impl for {:?}, from {:?}",
|
||||
self, impl_trait_ref);
|
||||
|
||||
// Record the write into the impl set, but only for local
|
||||
// impls: external impls are handled differently.
|
||||
if impl_def_id.is_local() {
|
||||
self.write_trait_impls(tcx);
|
||||
}
|
||||
|
||||
// We don't want to borrow_mut after we already populated all impls,
|
||||
// so check if an impl is present with an immutable borrow first.
|
||||
if let Some(sty) = fast_reject::simplify_type(tcx,
|
||||
impl_trait_ref.self_ty(), false) {
|
||||
if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
|
||||
if is.contains(&impl_def_id) {
|
||||
return // duplicate - skip
|
||||
}
|
||||
}
|
||||
|
||||
self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
|
||||
} else {
|
||||
if self.blanket_impls.borrow().contains(&impl_def_id) {
|
||||
return // duplicate - skip
|
||||
}
|
||||
self.blanket_impls.borrow_mut().push(impl_def_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &ty::ctxt<'tcx>, mut f: F) {
|
||||
self.read_trait_impls(tcx);
|
||||
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
|
||||
|
||||
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
|
||||
for v in self.nonblanket_impls.borrow().values() {
|
||||
for &impl_def_id in v {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over every impl that could possibly match the
|
||||
/// self-type `self_ty`.
|
||||
pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut f: F)
|
||||
{
|
||||
self.read_trait_impls(tcx);
|
||||
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
|
||||
|
||||
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
|
||||
// simplify_type(.., false) basically replaces type parameters and
|
||||
// projections with infer-variables. This is, of course, done on
|
||||
// the impl trait-ref when it is instantiated, but not on the
|
||||
// predicate trait-ref which is passed here.
|
||||
//
|
||||
// for example, if we match `S: Copy` against an impl like
|
||||
// `impl<T:Copy> Copy for Option<T>`, we replace the type variable
|
||||
// in `Option<T>` with an infer variable, to `Option<_>` (this
|
||||
// doesn't actually change fast_reject output), but we don't
|
||||
// replace `S` with anything - this impl of course can't be
|
||||
// selected, and as there are hundreds of similar impls,
|
||||
// considering them would significantly harm performance.
|
||||
if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
|
||||
if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
|
||||
for &impl_def_id in impls {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for v in self.nonblanket_impls.borrow().values() {
|
||||
for &impl_def_id in v {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_impl_lists<'s>(&'s self, tcx: &ty::ctxt<'tcx>)
|
||||
-> (Ref<'s, Vec<DefId>>,
|
||||
Ref<'s, FnvHashMap<fast_reject::SimplifiedType, Vec<DefId>>>) {
|
||||
self.read_trait_impls(tcx);
|
||||
(self.blanket_impls.borrow(), self.nonblanket_impls.borrow())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
flags TraitFlags: u32 {
|
||||
const NO_TRAIT_FLAGS = 0,
|
||||
const HAS_DEFAULT_IMPL = 1 << 0,
|
||||
const IS_OBJECT_SAFE = 1 << 1,
|
||||
const OBJECT_SAFETY_VALID = 1 << 2,
|
||||
const IMPLS_VALID = 1 << 3,
|
||||
}
|
||||
}
|
||||
|
|
@ -201,46 +201,38 @@ pub fn block_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr) -
|
|||
return v.flag;
|
||||
}
|
||||
|
||||
/// Memoizes a one-argument closure using the given RefCell containing
|
||||
/// a type implementing MutableMap to serve as a cache.
|
||||
///
|
||||
/// In the future the signature of this function is expected to be:
|
||||
/// ```
|
||||
/// pub fn memoized<T: Clone, U: Clone, M: MutableMap<T, U>>(
|
||||
/// cache: &RefCell<M>,
|
||||
/// f: &|T| -> U
|
||||
/// ) -> impl |T| -> U {
|
||||
/// ```
|
||||
/// but currently it is not possible.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// struct Context {
|
||||
/// cache: RefCell<HashMap<usize, usize>>
|
||||
/// }
|
||||
///
|
||||
/// fn factorial(ctxt: &Context, n: usize) -> usize {
|
||||
/// memoized(&ctxt.cache, n, |n| match n {
|
||||
/// 0 | 1 => n,
|
||||
/// _ => factorial(ctxt, n - 2) + factorial(ctxt, n - 1)
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn memoized<T, U, S, F>(cache: &RefCell<HashMap<T, U, S>>, arg: T, f: F) -> U
|
||||
where T: Clone + Hash + Eq,
|
||||
U: Clone,
|
||||
S: HashState,
|
||||
F: FnOnce(T) -> U,
|
||||
pub trait MemoizationMap {
|
||||
type Key: Clone;
|
||||
type Value: Clone;
|
||||
|
||||
/// If `key` is present in the map, return the valuee,
|
||||
/// otherwise invoke `op` and store the value in the map.
|
||||
///
|
||||
/// NB: if the receiver is a `DepTrackingMap`, special care is
|
||||
/// needed in the `op` to ensure that the correct edges are
|
||||
/// added into the dep graph. See the `DepTrackingMap` impl for
|
||||
/// more details!
|
||||
fn memoize<OP>(&self, key: Self::Key, op: OP) -> Self::Value
|
||||
where OP: FnOnce() -> Self::Value;
|
||||
}
|
||||
|
||||
impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>>
|
||||
where K: Hash+Eq+Clone, V: Clone, S: HashState
|
||||
{
|
||||
let key = arg.clone();
|
||||
let result = cache.borrow().get(&key).cloned();
|
||||
match result {
|
||||
Some(result) => result,
|
||||
None => {
|
||||
let result = f(arg);
|
||||
cache.borrow_mut().insert(key, result.clone());
|
||||
result
|
||||
type Key = K;
|
||||
type Value = V;
|
||||
|
||||
fn memoize<OP>(&self, key: K, op: OP) -> V
|
||||
where OP: FnOnce() -> V
|
||||
{
|
||||
let result = self.borrow().get(&key).cloned();
|
||||
match result {
|
||||
Some(result) => result,
|
||||
None => {
|
||||
let result = op();
|
||||
self.borrow_mut().insert(key, result.clone());
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ use middle::ty::{self, RegionEscape, Ty};
|
|||
use rustc::mir;
|
||||
use rustc::mir::visit::MutVisitor;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::Cell;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
|
@ -353,16 +353,11 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
|
|||
let associated_type_names = parse_associated_type_names(item_doc);
|
||||
let paren_sugar = parse_paren_sugar(item_doc);
|
||||
|
||||
ty::TraitDef {
|
||||
paren_sugar: paren_sugar,
|
||||
unsafety: unsafety,
|
||||
generics: generics,
|
||||
trait_ref: item_trait_ref(item_doc, tcx, cdata),
|
||||
associated_type_names: associated_type_names,
|
||||
nonblanket_impls: RefCell::new(FnvHashMap()),
|
||||
blanket_impls: RefCell::new(vec![]),
|
||||
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
|
||||
}
|
||||
ty::TraitDef::new(unsafety,
|
||||
paren_sugar,
|
||||
generics,
|
||||
item_trait_ref(item_doc, tcx, cdata),
|
||||
associated_type_names)
|
||||
}
|
||||
|
||||
pub fn get_adt_def<'tcx>(intr: &IdentInterner,
|
||||
|
|
|
@ -75,11 +75,11 @@ use middle::ty::util::IntTypeExt;
|
|||
use rscope::*;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::front::map as hir_map;
|
||||
use util::common::{ErrorReported, memoized};
|
||||
use util::common::{ErrorReported, MemoizationMap};
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
use write_ty_to_tcx;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -1419,17 +1419,17 @@ fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
}
|
||||
|
||||
fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
it: &hir::Item)
|
||||
item: &hir::Item)
|
||||
-> ty::TypeScheme<'tcx>
|
||||
{
|
||||
// Computing the type scheme of an item is a discrete task:
|
||||
let item_def_id = ccx.tcx.map.local_def_id(it.id);
|
||||
let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeScheme(item_def_id));
|
||||
ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // we have access to `it`
|
||||
|
||||
memoized(&ccx.tcx.tcache,
|
||||
ccx.tcx.map.local_def_id(it.id),
|
||||
|_| compute_type_scheme_of_item(ccx, it))
|
||||
let item_def_id = ccx.tcx.map.local_def_id(item.id);
|
||||
ccx.tcx.tcache.memoize(item_def_id, || {
|
||||
// NB. Since the `memoized` function enters a new task, and we
|
||||
// are giving this task access to the item `item`, we must
|
||||
// register a read.
|
||||
ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
|
||||
compute_type_scheme_of_item(ccx, item)
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
|
@ -1547,14 +1547,14 @@ fn type_scheme_of_foreign_item<'a, 'tcx>(
|
|||
abi: abi::Abi)
|
||||
-> ty::TypeScheme<'tcx>
|
||||
{
|
||||
// Computing the type scheme of a foreign item is a discrete task:
|
||||
let item_def_id = ccx.tcx.map.local_def_id(item.id);
|
||||
let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeScheme(item_def_id));
|
||||
ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // we have access to `item`
|
||||
|
||||
memoized(&ccx.tcx.tcache,
|
||||
ccx.tcx.map.local_def_id(item.id),
|
||||
|_| compute_type_scheme_of_foreign_item(ccx, item, abi))
|
||||
ccx.tcx.tcache.memoize(item_def_id, || {
|
||||
// NB. Since the `memoized` function enters a new task, and we
|
||||
// are giving this task access to the item `item`, we must
|
||||
// register a read.
|
||||
ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
|
||||
compute_type_scheme_of_foreign_item(ccx, item, abi)
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_type_scheme_of_foreign_item<'a, 'tcx>(
|
||||
|
|
Loading…
Reference in a new issue