@@ -18,7 +18,7 @@ one of three things:
18
18
1 . HIR nodes (like ` Hir(DefId) ` ) represent the HIR input itself.
19
19
2 . Data nodes (like ` ItemSignature(DefId) ` ) represent some computed
20
20
information about a particular item.
21
- 3 . Procedure notes (like ` CoherenceCheckImpl (DefId)` ) represent some
21
+ 3 . Procedure nodes (like ` CoherenceCheckTrait (DefId)` ) represent some
22
22
procedure that is executing. Usually this procedure is
23
23
performing some kind of check for errors. You can think of them as
24
24
computed values where the value being computed is ` () ` (and the
@@ -57,139 +57,10 @@ recompile that item for sure. But we need the dep tracking map to tell
57
57
us what * else* we have to recompile. Shared state is anything that is
58
58
used to communicate results from one item to another.
59
59
60
- ### Identifying the current task
60
+ ### Identifying the current task, tracking reads/writes, etc
61
61
62
- The dep graph always tracks a current task: this is basically the
63
- ` DepNode ` that the compiler is computing right now. Typically it would
64
- be a procedure node, but it can also be a data node (as noted above,
65
- the two are kind of equivalent).
66
-
67
- You set the current task by calling ` dep_graph.in_task(node) ` . For example:
68
-
69
- ``` rust
70
- let _task = tcx . dep_graph. in_task (DepNode :: Privacy );
71
- ```
72
-
73
- Now all the code until ` _task ` goes out of scope will be considered
74
- part of the "privacy task".
75
-
76
- The tasks are maintained in a stack, so it is perfectly fine to nest
77
- one task within another. Because pushing a task is considered to be
78
- computing a value, when you nest a task ` N2 ` inside of a task ` N1 ` , we
79
- automatically add an edge ` N2 -> N1 ` (since ` N1 ` presumably needed the
80
- result of ` N2 ` to complete):
81
-
82
- ``` rust
83
- let _n1 = tcx . dep_graph. in_task (DepNode :: N1 );
84
- let _n2 = tcx . dep_graph. in_task (DepNode :: N2 );
85
- // this will result in an edge N1 -> n2
86
- ```
87
-
88
- ### Ignore tasks
89
-
90
- Although it is rarely needed, you can also push a special "ignore"
91
- task:
92
-
93
- ``` rust
94
- let _ignore = tc . dep_graph. in_ignore ();
95
- ```
96
-
97
- This will cause all read/write edges to be ignored until it goes out
98
- of scope or until something else is pushed. For example, we could
99
- suppress the edge between nested tasks like so:
100
-
101
- ``` rust
102
- let _n1 = tcx . dep_graph. in_task (DepNode :: N1 );
103
- let _ignore = tcx . dep_graph. in_ignore ();
104
- let _n2 = tcx . dep_graph. in_task (DepNode :: N2 );
105
- // now no edge is added
106
- ```
107
-
108
- ### Tracking reads and writes
109
-
110
- We need to identify what shared state is read/written by the current
111
- task as it executes. The most fundamental way of doing that is to invoke
112
- the ` read ` and ` write ` methods on ` DepGraph ` :
113
-
114
- ``` rust
115
- // Adds an edge from DepNode::Hir(some_def_id) to the current task
116
- tcx . dep_graph. read (DepNode :: Hir (some_def_id ))
117
-
118
- // Adds an edge from the current task to DepNode::ItemSignature(some_def_id)
119
- tcx . dep_graph. write (DepNode :: ItemSignature (some_def_id ))
120
- ```
121
-
122
- However, you should rarely need to invoke those methods directly.
123
- Instead, the idea is to * encapsulate* shared state into some API that
124
- will invoke ` read ` and ` write ` automatically. The most common way to
125
- do this is to use a ` DepTrackingMap ` , described in the next section,
126
- but any sort of abstraction barrier will do. In general, the strategy
127
- is that getting access to information implicitly adds an appropriate
128
- ` read ` . So, for example, when you use the
129
- ` dep_graph::visit_all_items_in_krate ` helper method, it will visit
130
- each item ` X ` , start a task ` Foo(X) ` for that item, and automatically
131
- add an edge ` Hir(X) -> Foo(X) ` . This edge is added because the code is
132
- being given access to the HIR node for ` X ` , and hence it is expected
133
- to read from it. Similarly, reading from the ` tcache ` map for item ` X `
134
- (which is a ` DepTrackingMap ` , described below) automatically invokes
135
- ` dep_graph.read(ItemSignature(X)) ` .
136
-
137
- ** Note:** adding ` Hir ` nodes requires a bit of caution due to the
138
- "inlining" that old trans and constant evaluation still use. See the
139
- section on inlining below.
140
-
141
- To make this strategy work, a certain amount of indirection is
142
- required. For example, modules in the HIR do not have direct pointers
143
- to the items that they contain. Rather, they contain node-ids -- one
144
- can then ask the HIR map for the item with a given node-id. This gives
145
- us an opportunity to add an appropriate read edge.
146
-
147
- #### Explicit calls to read and write when starting a new subtask
148
-
149
- One time when you * may* need to call ` read ` and ` write ` directly is
150
- when you push a new task onto the stack, either by calling ` in_task `
151
- as shown above or indirectly, such as with the ` memoize ` pattern
152
- described below. In that case, any data that the task has access to
153
- from the surrounding environment must be explicitly "read". For
154
- example, in ` librustc_typeck ` , the collection code visits all items
155
- and, among other things, starts a subtask producing its signature
156
- (what follows is simplified pseudocode, of course):
157
-
158
- ``` rust
159
- fn visit_item (item : & hir :: Item ) {
160
- // Here, current subtask is "Collect(X)", and an edge Hir(X) -> Collect(X)
161
- // has automatically been added by `visit_all_items_in_krate`.
162
- let sig = signature_of_item (item );
163
- }
164
-
165
- fn signature_of_item (item : & hir :: Item ) {
166
- let def_id = tcx . map. local_def_id (item . id);
167
- let task = tcx . dep_graph. in_task (DepNode :: ItemSignature (def_id ));
168
- tcx . dep_graph. read (DepNode :: Hir (def_id )); // <-- the interesting line
169
- ...
170
- }
171
- ```
172
-
173
- Here you can see that, in ` signature_of_item ` , we started a subtask
174
- corresponding to producing the ` ItemSignature ` . This subtask will read from
175
- ` item ` -- but it gained access to ` item ` implicitly. This means that if it just
176
- reads from ` item ` , there would be missing edges in the graph:
177
-
178
- Hir(X) --+ // added by the explicit call to `read`
179
- | |
180
- | +---> ItemSignature(X) -> Collect(X)
181
- | ^
182
- | |
183
- +---------------------------------+ // added by `visit_all_items_in_krate`
184
-
185
- In particular, the edge from ` Hir(X) ` to ` ItemSignature(X) ` is only
186
- present because we called ` read ` ourselves when entering the ` ItemSignature(X) `
187
- task.
188
-
189
- So, the rule of thumb: when entering a new task yourself, register
190
- reads on any shared state that you inherit. (This actually comes up
191
- fairly infrequently though: the main place you need caution is around
192
- memoization.)
62
+ FIXME(#42293 ). This text needs to be rewritten for the new red-green
63
+ system, which doesn't fully exist yet.
193
64
194
65
#### Dependency tracking map
195
66
0 commit comments