@@ -66,6 +66,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
6666use rustc_hir:: definitions:: DefPathHash ;
6767use rustc_hir:: HirId ;
6868use rustc_span:: symbol:: Symbol ;
69+ use rustc_span:: DUMMY_SP ;
6970use std:: hash:: Hash ;
7071
7172pub use rustc_query_system:: dep_graph:: { DepContext , DepNodeParams } ;
@@ -95,6 +96,50 @@ pub struct DepKindStruct {
9596 // can be made a specialized associated const.
9697 can_reconstruct_query_key : fn ( ) -> bool ,
9798
99+ /// The red/green evaluation system will try to mark a specific DepNode in the
100+ /// dependency graph as green by recursively trying to mark the dependencies of
101+ /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
102+ /// where we don't know if it is red or green and we therefore actually have
103+ /// to recompute its value in order to find out. Since the only piece of
104+ /// information that we have at that point is the `DepNode` we are trying to
105+ /// re-evaluate, we need some way to re-run a query from just that. This is what
106+ /// `force_from_dep_node()` implements.
107+ ///
108+ /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
109+ /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
110+ /// is usually constructed by computing a stable hash of the query-key that the
111+ /// `DepNode` corresponds to. Consequently, it is not in general possible to go
112+ /// back from hash to query-key (since hash functions are not reversible). For
113+ /// this reason `force_from_dep_node()` is expected to fail from time to time
114+ /// because we just cannot find out, from the `DepNode` alone, what the
115+ /// corresponding query-key is and therefore cannot re-run the query.
116+ ///
117+ /// The system deals with this case letting `try_mark_green` fail which forces
118+ /// the root query to be re-evaluated.
119+ ///
120+ /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
121+ /// Fortunately, we can use some contextual information that will allow us to
122+ /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
123+ /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
124+ /// valid `DefPathHash`. Since we also always build a huge table that maps every
125+ /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
126+ /// everything we need to re-run the query.
127+ ///
128+ /// Take the `mir_promoted` query as an example. Like many other queries, it
129+ /// just has a single parameter: the `DefId` of the item it will compute the
130+ /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
131+ /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
132+ /// is actually a `DefPathHash`, and can therefore just look up the corresponding
133+ /// `DefId` in `tcx.def_path_hash_to_def_id`.
134+ ///
135+ /// When you implement a new query, it will likely have a corresponding new
136+ /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
137+ /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
138+ /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
139+ /// add it to the "We don't have enough information to reconstruct..." group in
140+ /// the match below.
141+ pub ( super ) force_from_dep_node : fn ( tcx : TyCtxt < ' _ > , dep_node : & DepNode ) -> bool ,
142+
98143 /// Invoke a query to put the on-disk cached value in memory.
99144 pub ( super ) try_load_from_on_disk_cache : fn ( TyCtxt < ' _ > , & DepNode ) ,
100145}
@@ -156,7 +201,7 @@ macro_rules! contains_eval_always_attr {
156201pub mod dep_kind {
157202 use super :: * ;
158203 use crate :: ty:: query:: { queries, query_keys} ;
159- use rustc_query_system:: query:: QueryDescription ;
204+ use rustc_query_system:: query:: { force_query , QueryDescription } ;
160205
161206 // We use this for most things when incr. comp. is turned off.
162207 pub const Null : DepKindStruct = DepKindStruct {
@@ -165,6 +210,7 @@ pub mod dep_kind {
165210 is_eval_always : false ,
166211
167212 can_reconstruct_query_key : || true ,
213+ force_from_dep_node : |_, dep_node| bug ! ( "force_from_dep_node: encountered {:?}" , dep_node) ,
168214 try_load_from_on_disk_cache : |_, _| { } ,
169215 } ;
170216
@@ -175,6 +221,7 @@ pub mod dep_kind {
175221 is_eval_always : true ,
176222
177223 can_reconstruct_query_key : || true ,
224+ force_from_dep_node : |_, dep_node| bug ! ( "force_from_dep_node: encountered {:?}" , dep_node) ,
178225 try_load_from_on_disk_cache : |_, _| { } ,
179226 } ;
180227
@@ -184,6 +231,7 @@ pub mod dep_kind {
184231 is_eval_always : false ,
185232
186233 can_reconstruct_query_key : || false ,
234+ force_from_dep_node : |_, _| false ,
187235 try_load_from_on_disk_cache : |_, _| { } ,
188236 } ;
189237
@@ -193,6 +241,7 @@ pub mod dep_kind {
193241 is_eval_always : false ,
194242
195243 can_reconstruct_query_key : || false ,
244+ force_from_dep_node : |_, _| false ,
196245 try_load_from_on_disk_cache : |_, _| { } ,
197246 } ;
198247
@@ -217,6 +266,24 @@ pub mod dep_kind {
217266 <query_keys:: $variant<' _> as DepNodeParams <TyCtxt <' _>>>:: recover( tcx, dep_node)
218267 }
219268
269+ fn force_from_dep_node( tcx: TyCtxt <' _>, dep_node: & DepNode ) -> bool {
270+ if !can_reconstruct_query_key( ) {
271+ return false ;
272+ }
273+
274+ if let Some ( key) = recover( tcx, dep_node) {
275+ force_query:: <queries:: $variant<' _>, _>(
276+ tcx,
277+ key,
278+ DUMMY_SP ,
279+ * dep_node
280+ ) ;
281+ return true ;
282+ }
283+
284+ false
285+ }
286+
220287 fn try_load_from_on_disk_cache( tcx: TyCtxt <' _>, dep_node: & DepNode ) {
221288 if !can_reconstruct_query_key( ) {
222289 return
@@ -238,6 +305,7 @@ pub mod dep_kind {
238305 is_anon,
239306 is_eval_always,
240307 can_reconstruct_query_key,
308+ force_from_dep_node,
241309 try_load_from_on_disk_cache,
242310 }
243311 } ; ) *
0 commit comments