we were using interior mutability (RefCells, TyIvar), add some reads/writes.
use std::ops::Index;
use std::hash::Hash;
use std::marker::PhantomData;
+use util::common::MemoizationMap;
use super::{DepNode, DepGraph};
}
}
+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;
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;
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>,
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;
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
/// 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>,
/// 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.
/// 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>,
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>>,
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()),
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)
+ })
+ })
+ }
}
// 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;
/// (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>>);
}
#[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;
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>)")
}
--- /dev/null
+// 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> }
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;
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;
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;
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,
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>
}
}
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);
}
}
/// 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 {
}
}
- 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) {
}
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 {
|| 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,
--- /dev/null
+// 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,
+ }
+}
+
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
+ }
}
}
}
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;
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,
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;
}
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>,
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>(