]> git.lizzy.rs Git - rust.git/blob - src/librustc/dep_graph/dep_tracking_map.rs
Rollup merge of #57740 - JakubOnderka:ipv4addr-to_ne_bytes, r=scottmcm
[rust.git] / src / librustc / dep_graph / dep_tracking_map.rs
1 use rustc_data_structures::fx::FxHashMap;
2 use std::cell::RefCell;
3 use std::hash::Hash;
4 use std::marker::PhantomData;
5 use crate::util::common::MemoizationMap;
6
7 use super::{DepKind, DepNodeIndex, DepGraph};
8
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>,
14     graph: DepGraph,
15     map: FxHashMap<M::Key, (M::Value, DepNodeIndex)>,
16 }
17
18 pub trait DepTrackingMapConfig {
19     type Key: Eq + Hash + Clone;
20     type Value: Clone;
21     fn to_dep_kind() -> DepKind;
22 }
23
24 impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
25     pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
26         DepTrackingMap {
27             phantom: PhantomData,
28             graph,
29             map: Default::default(),
30         }
31     }
32 }
33
34 impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
35     type Key = M::Key;
36     type Value = M::Value;
37
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:
41     ///
42     ///     [op] -> Map(key) -> CurrentTask
43     ///
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.
48     ///
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:
55     ///
56     /// ```
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)
62     ///     });
63     /// }
64     /// ```
65     ///
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
71     {
72         let graph;
73         {
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();
78             }
79             graph = this.graph.clone();
80         }
81
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);
85         result
86     }
87 }