]> git.lizzy.rs Git - rust.git/blob - src/librustc/dep_graph/mod.rs
d37a4acbcfb3a81201cca9f1bb2d9f5c3b40f667
[rust.git] / src / librustc / dep_graph / mod.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use self::thread::{DepGraphThreadData, DepMessage};
12 use middle::def_id::DefId;
13 use middle::ty;
14 use rustc_front::hir;
15 use rustc_front::intravisit::Visitor;
16 use std::rc::Rc;
17
18 mod dep_tracking_map;
19 mod edges;
20 mod query;
21 mod raii;
22 mod thread;
23
24 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
25 pub enum DepNode {
26     // Represents the `Krate` as a whole (the `hir::Krate` value) (as
27     // distinct from the krate module). This is basically a hash of
28     // the entire krate, so if you read from `Krate` (e.g., by calling
29     // `tcx.map.krate()`), we will have to assume that any change
30     // means that you need to be recompiled. This is because the
31     // `Krate` value gives you access to all other items. To avoid
32     // this fate, do not call `tcx.map.krate()`; instead, prefer
33     // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
34     // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
35     // access to the krate, but you must remember to add suitable
36     // edges yourself for the individual items that you read.
37     Krate,
38
39     // Represents the HIR node with the given node-id
40     Hir(DefId),
41
42     // Represents different phases in the compiler.
43     CollectItem(DefId),
44     Coherence,
45     CoherenceCheckImpl(DefId),
46     CoherenceOverlapCheck(DefId),
47     CoherenceOverlapCheckSpecial(DefId),
48     CoherenceOrphanCheck(DefId),
49     Variance,
50     WfCheck(DefId),
51     TypeckItemType(DefId),
52     TypeckItemBody(DefId),
53     Dropck,
54     DropckImpl(DefId),
55     CheckConst(DefId),
56     Privacy,
57     IntrinsicCheck(DefId),
58     MatchCheck(DefId),
59     MirMapConstruction(DefId),
60     BorrowCheck(DefId),
61     RvalueCheck(DefId),
62     Reachability,
63     DeadCheck,
64     StabilityCheck,
65     LateLintCheck,
66     IntrinsicUseCheck,
67     TransCrate,
68     TransCrateItem(DefId),
69     TransInlinedItem(DefId),
70     TransWriteMetadata,
71
72     // Nodes representing bits of computed IR in the tcx. Each shared
73     // table in the tcx (or elsewhere) maps to one of these
74     // nodes. Often we map multiple tables to the same node if there
75     // is no point in distinguishing them (e.g., both the type and
76     // predicates for an item wind up in `ItemSignature`). Other
77     // times, such as `ImplItems` vs `TraitItemDefIds`, tables which
78     // might be mergable are kept distinct because the sets of def-ids
79     // to which they apply are disjoint, and hence we might as well
80     // have distinct labels for easier debugging.
81     ImplOrTraitItems(DefId),
82     ItemSignature(DefId),
83     FieldTy(DefId),
84     TraitItemDefIds(DefId),
85     InherentImpls(DefId),
86     ImplItems(DefId),
87
88     // The set of impls for a given trait. Ultimately, it would be
89     // nice to get more fine-grained here (e.g., to include a
90     // simplified type), but we can't do that until we restructure the
91     // HIR to distinguish the *header* of an impl from its body.  This
92     // is because changes to the header may change the self-type of
93     // the impl and hence would require us to be more conservative
94     // than changes in the impl body.
95     TraitImpls(DefId),
96
97     // Nodes representing caches. To properly handle a true cache, we
98     // don't use a DepTrackingMap, but rather we push a task node.
99     // Otherwise the write into the map would be incorrectly
100     // attributed to the first task that happened to fill the cache,
101     // which would yield an overly conservative dep-graph.
102     TraitItems(DefId),
103     ReprHints(DefId),
104     TraitSelect(DefId),
105 }
106
107 #[derive(Clone)]
108 pub struct DepGraph {
109     data: Rc<DepGraphThreadData>
110 }
111
112 impl DepGraph {
113     pub fn new(enabled: bool) -> DepGraph {
114         DepGraph {
115             data: Rc::new(DepGraphThreadData::new(enabled))
116         }
117     }
118
119     /// True if we are actually building a dep-graph. If this returns false,
120     /// then the other methods on this `DepGraph` will have no net effect.
121     #[inline]
122     pub fn enabled(&self) -> bool {
123         self.data.enabled()
124     }
125
126     pub fn query(&self) -> DepGraphQuery {
127         self.data.query()
128     }
129
130     pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
131         raii::IgnoreTask::new(&self.data)
132     }
133
134     pub fn in_task<'graph>(&'graph self, key: DepNode) -> raii::DepTask<'graph> {
135         raii::DepTask::new(&self.data, key)
136     }
137
138     pub fn with_ignore<OP,R>(&self, op: OP) -> R
139         where OP: FnOnce() -> R
140     {
141         let _task = self.in_ignore();
142         op()
143     }
144
145     pub fn with_task<OP,R>(&self, key: DepNode, op: OP) -> R
146         where OP: FnOnce() -> R
147     {
148         let _task = self.in_task(key);
149         op()
150     }
151
152     pub fn read(&self, v: DepNode) {
153         self.data.enqueue(DepMessage::Read(v));
154     }
155
156     pub fn write(&self, v: DepNode) {
157         self.data.enqueue(DepMessage::Write(v));
158     }
159 }
160
161 pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
162
163 pub use self::query::DepGraphQuery;
164
165 /// Visit all the items in the krate in some order. When visiting a
166 /// particular item, first create a dep-node by calling `dep_node_fn`
167 /// and push that onto the dep-graph stack of tasks, and also create a
168 /// read edge from the corresponding AST node. This is used in
169 /// compiler passes to automatically record the item that they are
170 /// working on.
171 pub fn visit_all_items_in_krate<'tcx,V,F>(tcx: &ty::ctxt<'tcx>,
172                                           mut dep_node_fn: F,
173                                           visitor: &mut V)
174     where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
175 {
176     struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
177         tcx: &'visit ty::ctxt<'tcx>,
178         dep_node_fn: &'visit mut F,
179         visitor: &'visit mut V
180     }
181
182     impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
183         where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx>
184     {
185         fn visit_item(&mut self, i: &'tcx hir::Item) {
186             let item_def_id = self.tcx.map.local_def_id(i.id);
187             let task_id = (self.dep_node_fn)(item_def_id);
188             debug!("About to start task {:?}", task_id);
189             let _task = self.tcx.dep_graph.in_task(task_id);
190             self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
191             self.visitor.visit_item(i)
192         }
193     }
194
195     let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
196     let mut tracking_visitor = TrackingVisitor {
197         tcx: tcx,
198         dep_node_fn: &mut dep_node_fn,
199         visitor: visitor
200     };
201     krate.visit_all_items(&mut tracking_visitor)
202 }