1 use rustc_data_structures::fx::FxHashMap;
2 use std::cell::RefCell;
4 use std::marker::PhantomData;
5 use crate::util::common::MemoizationMap;
7 use super::{DepKind, DepNodeIndex, DepGraph};
9 /// A DepTrackingMap offers a subset of the `Map` API and ensures that
10 /// we make calls to `read` and `write` as appropriate. We key the
11 /// maps with a unique type for brevity.
12 pub struct DepTrackingMap<M: DepTrackingMapConfig> {
13 phantom: PhantomData<M>,
15 map: FxHashMap<M::Key, (M::Value, DepNodeIndex)>,
18 pub trait DepTrackingMapConfig {
19 type Key: Eq + Hash + Clone;
21 fn to_dep_kind() -> DepKind;
24 impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
25 pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
29 map: Default::default(),
34 impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
36 type Value = M::Value;
38 /// Memoizes an entry in the dep-tracking-map. If the entry is not
39 /// already present, then `op` will be executed to compute its value.
40 /// The resulting dependency graph looks like this:
42 /// [op] -> Map(key) -> CurrentTask
44 /// Here, `[op]` represents whatever nodes `op` reads in the
45 /// course of execution; `Map(key)` represents the node for this
46 /// map, and `CurrentTask` represents the current task when
47 /// `memoize` is invoked.
49 /// **Important:** when `op` is invoked, the current task will be
50 /// switched to `Map(key)`. Therefore, if `op` makes use of any
51 /// HIR nodes or shared state accessed through its closure
52 /// environment, it must explicitly register a read of that
53 /// state. As an example, see `type_of_item` in `collect`,
54 /// which looks something like this:
57 /// fn type_of_item(..., item: &hir::Item) -> Ty<'tcx> {
58 /// let item_def_id = ccx.tcx.hir().local_def_id(it.id);
59 /// ccx.tcx.item_types.memoized(item_def_id, || {
60 /// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
61 /// compute_type_of_item(ccx, item)
66 /// The key is the line marked `(*)`: the closure implicitly
67 /// accesses the body of the item `item`, so we register a read
68 /// from `Hir(item_def_id)`.
69 fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
70 where OP: FnOnce() -> M::Value
74 let this = self.borrow();
75 if let Some(&(ref result, dep_node)) = this.map.get(&key) {
76 this.graph.read_index(dep_node);
77 return result.clone();
79 graph = this.graph.clone();
82 let (result, dep_node) = graph.with_anon_task(M::to_dep_kind(), op);
83 self.borrow_mut().map.insert(key, (result.clone(), dep_node));
84 graph.read_index(dep_node);