@@ -176,46 +176,32 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
176
176
// Recreate the edges in the graph that are still clean.
177
177
let mut clean_work_products = FxHashSet ( ) ;
178
178
let mut dirty_work_products = FxHashSet ( ) ; // incomplete; just used to suppress debug output
179
+ let mut extra_edges = vec ! [ ] ;
179
180
for ( source, targets) in & edge_map {
180
181
for target in targets {
181
- // If the target is dirty, skip the edge. If this is an edge
182
- // that targets a work-product, we can print the blame
183
- // information now.
184
- if let Some ( blame) = dirty_raw_nodes. get ( target) {
185
- if let DepNode :: WorkProduct ( ref wp) = * target {
186
- if tcx. sess . opts . debugging_opts . incremental_info {
187
- if dirty_work_products. insert ( wp. clone ( ) ) {
188
- // It'd be nice to pretty-print these paths better than just
189
- // using the `Debug` impls, but wev.
190
- println ! ( "incremental: module {:?} is dirty because {:?} \
191
- changed or was removed",
192
- wp,
193
- blame. map_def( |& index| {
194
- Some ( directory. def_path_string( tcx, index) )
195
- } ) . unwrap( ) ) ;
196
- }
197
- }
198
- }
199
- continue ;
200
- }
201
-
202
- // If the source is dirty, the target will be dirty.
203
- assert ! ( !dirty_raw_nodes. contains_key( source) ) ;
204
-
205
- // Retrace the source -> target edges to def-ids and then
206
- // create an edge in the graph. Retracing may yield none if
207
- // some of the data happens to have been removed; this ought
208
- // to be impossible unless it is dirty, so we can unwrap.
209
- let source_node = retraced. map ( source) . unwrap ( ) ;
210
- let target_node = retraced. map ( target) . unwrap ( ) ;
211
- let _task = tcx. dep_graph . in_task ( target_node) ;
212
- tcx. dep_graph . read ( source_node) ;
213
- if let DepNode :: WorkProduct ( ref wp) = * target {
214
- clean_work_products. insert ( wp. clone ( ) ) ;
215
- }
182
+ process_edges ( tcx, source, target, & edge_map, & directory, & retraced, & dirty_raw_nodes,
183
+ & mut clean_work_products, & mut dirty_work_products, & mut extra_edges) ;
216
184
}
217
185
}
218
186
187
+ // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph.
188
+ // This is pretty unusual but it arises in a scenario like this:
189
+ //
190
+ // Hir(X) -> Foo(Y) -> Bar
191
+ //
192
+ // Note that the `Hir(Y)` is not an input to `Foo(Y)` -- this
193
+ // almost never happens, but can happen in some obscure
194
+ // scenarios. In that case, if `Y` is removed, then we can't
195
+ // recreate `Foo(Y)` (the def-id `Y` no longer exists); what we do
196
+ // then is to push the edge `Hir(X) -> Bar` onto `extra_edges`
197
+ // (along with any other targets of `Foo(Y)`). We will then add
198
+ // the edge from `Hir(X)` to `Bar` (or, if `Bar` itself cannot be
199
+ // recreated, to the targets of `Bar`).
200
+ while let Some ( ( source, target) ) = extra_edges. pop ( ) {
201
+ process_edges ( tcx, source, target, & edge_map, & directory, & retraced, & dirty_raw_nodes,
202
+ & mut clean_work_products, & mut dirty_work_products, & mut extra_edges) ;
203
+ }
204
+
219
205
// Add in work-products that are still clean, and delete those that are
220
206
// dirty.
221
207
reconcile_work_products ( tcx, work_products, & clean_work_products) ;
@@ -393,3 +379,66 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
393
379
serialized_hashes. index_map. len( ) ) ;
394
380
}
395
381
382
+ fn process_edges < ' a , ' tcx , ' edges > (
383
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
384
+ source : & ' edges DepNode < DefPathIndex > ,
385
+ target : & ' edges DepNode < DefPathIndex > ,
386
+ edges : & ' edges FxHashMap < DepNode < DefPathIndex > , Vec < DepNode < DefPathIndex > > > ,
387
+ directory : & DefIdDirectory ,
388
+ retraced : & RetracedDefIdDirectory ,
389
+ dirty_raw_nodes : & DirtyNodes ,
390
+ clean_work_products : & mut FxHashSet < Arc < WorkProductId > > ,
391
+ dirty_work_products : & mut FxHashSet < Arc < WorkProductId > > ,
392
+ extra_edges : & mut Vec < ( & ' edges DepNode < DefPathIndex > , & ' edges DepNode < DefPathIndex > ) > )
393
+ {
394
+ // If the target is dirty, skip the edge. If this is an edge
395
+ // that targets a work-product, we can print the blame
396
+ // information now.
397
+ if let Some ( blame) = dirty_raw_nodes. get ( target) {
398
+ if let DepNode :: WorkProduct ( ref wp) = * target {
399
+ if tcx. sess . opts . debugging_opts . incremental_info {
400
+ if dirty_work_products. insert ( wp. clone ( ) ) {
401
+ // It'd be nice to pretty-print these paths better than just
402
+ // using the `Debug` impls, but wev.
403
+ println ! ( "incremental: module {:?} is dirty because {:?} \
404
+ changed or was removed",
405
+ wp,
406
+ blame. map_def( |& index| {
407
+ Some ( directory. def_path_string( tcx, index) )
408
+ } ) . unwrap( ) ) ;
409
+ }
410
+ }
411
+ }
412
+ return ;
413
+ }
414
+
415
+ // If the source is dirty, the target will be dirty.
416
+ assert ! ( !dirty_raw_nodes. contains_key( source) ) ;
417
+
418
+ // Retrace the source -> target edges to def-ids and then create
419
+ // an edge in the graph. Retracing may yield none if some of the
420
+ // data happens to have been removed.
421
+ if let Some ( source_node) = retraced. map ( source) {
422
+ if let Some ( target_node) = retraced. map ( target) {
423
+ let _task = tcx. dep_graph . in_task ( target_node) ;
424
+ tcx. dep_graph . read ( source_node) ;
425
+ if let DepNode :: WorkProduct ( ref wp) = * target {
426
+ clean_work_products. insert ( wp. clone ( ) ) ;
427
+ }
428
+ } else {
429
+ // As discussed in `decode_dep_graph` above, sometimes the
430
+ // target cannot be recreated again, in which case we add
431
+ // edges to go from `source` to the targets of `target`.
432
+ extra_edges. extend (
433
+ edges[ target] . iter ( ) . map ( |t| ( source, t) ) ) ;
434
+ }
435
+ } else {
436
+ // It's also possible that the source can't be created! But we
437
+ // can ignore such cases, because (a) if `source` is a HIR
438
+ // node, it would be considered dirty; and (b) in other cases,
439
+ // there must be some input to this node that is clean, and so
440
+ // we'll re-create the edges over in the case where target is
441
+ // undefined.
442
+ }
443
+ }
444
+
0 commit comments