@@ -65,6 +65,12 @@ pub enum ProcessResult<O, E> {
65
65
Error ( E ) ,
66
66
}
67
67
68
+ #[ derive( Clone , Copy , PartialEq , Eq , Hash , Debug ) ]
69
+ struct ObligationTreeId ( usize ) ;
70
+
71
+ type ObligationTreeIdGenerator =
72
+ :: std:: iter:: Map < :: std:: ops:: RangeFrom < usize > , fn ( usize ) -> ObligationTreeId > ;
73
+
68
74
pub struct ObligationForest < O : ForestObligation > {
69
75
/// The list of obligations. In between calls to
70
76
/// `process_obligations`, this list only contains nodes in the
@@ -79,11 +85,25 @@ pub struct ObligationForest<O: ForestObligation> {
79
85
/// at a higher index than its parent. This is needed by the
80
86
/// backtrace iterator (which uses `split_at`).
81
87
nodes : Vec < Node < O > > ,
88
+
82
89
/// A cache of predicates that have been successfully completed.
83
90
done_cache : FxHashSet < O :: Predicate > ,
91
+
84
92
/// An cache of the nodes in `nodes`, indexed by predicate.
85
93
waiting_cache : FxHashMap < O :: Predicate , NodeIndex > ,
94
+
86
95
scratch : Option < Vec < usize > > ,
96
+
97
+ obligation_tree_id_generator : ObligationTreeIdGenerator ,
98
+
99
+ /// Per tree error cache. This is used to deduplicate errors,
100
+ /// which is necessary to avoid trait resolution overflow in
101
+ /// some cases.
102
+ ///
103
+ /// See [this][details] for details.
104
+ ///
105
+ /// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780
106
+ error_cache : FxHashMap < ObligationTreeId , FxHashSet < O :: Predicate > > ,
87
107
}
88
108
89
109
#[ derive( Debug ) ]
@@ -99,6 +119,9 @@ struct Node<O> {
99
119
/// Obligations that depend on this obligation for their
100
120
/// completion. They must all be in a non-pending state.
101
121
dependents : Vec < NodeIndex > ,
122
+
123
+ /// Identifier of the obligation tree to which this node belongs.
124
+ obligation_tree_id : ObligationTreeId ,
102
125
}
103
126
104
127
/// The state of one node in some tree within the forest. This
@@ -165,6 +188,8 @@ impl<O: ForestObligation> ObligationForest<O> {
165
188
done_cache : FxHashSet ( ) ,
166
189
waiting_cache : FxHashMap ( ) ,
167
190
scratch : Some ( vec ! [ ] ) ,
191
+ obligation_tree_id_generator : ( 0 ..) . map ( |i| ObligationTreeId ( i) ) ,
192
+ error_cache : FxHashMap ( ) ,
168
193
}
169
194
}
170
195
@@ -214,9 +239,29 @@ impl<O: ForestObligation> ObligationForest<O> {
214
239
Entry :: Vacant ( v) => {
215
240
debug ! ( "register_obligation_at({:?}, {:?}) - ok, new index is {}" ,
216
241
obligation, parent, self . nodes. len( ) ) ;
217
- v. insert ( NodeIndex :: new ( self . nodes . len ( ) ) ) ;
218
- self . nodes . push ( Node :: new ( parent, obligation) ) ;
219
- Ok ( ( ) )
242
+
243
+ let obligation_tree_id = match parent {
244
+ Some ( p) => {
245
+ let parent_node = & self . nodes [ p. get ( ) ] ;
246
+ parent_node. obligation_tree_id
247
+ }
248
+ None => self . obligation_tree_id_generator . next ( ) . unwrap ( )
249
+ } ;
250
+
251
+ let already_failed =
252
+ parent. is_some ( )
253
+ && self . error_cache
254
+ . get ( & obligation_tree_id)
255
+ . map ( |errors| errors. contains ( obligation. as_predicate ( ) ) )
256
+ . unwrap_or ( false ) ;
257
+
258
+ if already_failed {
259
+ Err ( ( ) )
260
+ } else {
261
+ v. insert ( NodeIndex :: new ( self . nodes . len ( ) ) ) ;
262
+ self . nodes . push ( Node :: new ( parent, obligation, obligation_tree_id) ) ;
263
+ Ok ( ( ) )
264
+ }
220
265
}
221
266
}
222
267
}
@@ -251,6 +296,15 @@ impl<O: ForestObligation> ObligationForest<O> {
251
296
. collect ( )
252
297
}
253
298
299
+ fn insert_into_error_cache ( & mut self , node_index : usize ) {
300
+ let node = & self . nodes [ node_index] ;
301
+
302
+ self . error_cache
303
+ . entry ( node. obligation_tree_id )
304
+ . or_insert_with ( || FxHashSet ( ) )
305
+ . insert ( node. obligation . as_predicate ( ) . clone ( ) ) ;
306
+ }
307
+
254
308
/// Perform a pass through the obligation list. This must
255
309
/// be called in a loop until `outcome.stalled` is false.
256
310
///
@@ -264,22 +318,15 @@ impl<O: ForestObligation> ObligationForest<O> {
264
318
let mut stalled = true ;
265
319
266
320
for index in 0 ..self . nodes . len ( ) {
267
- debug ! ( "process_obligations: node {} == {:?}" ,
268
- index,
269
- self . nodes[ index] ) ;
321
+ debug ! ( "process_obligations: node {} == {:?}" , index, self . nodes[ index] ) ;
270
322
271
323
let result = match self . nodes [ index] {
272
- Node { ref state, ref mut obligation, .. }
273
- if state. get ( ) == NodeState :: Pending =>
274
- {
275
- processor. process_obligation ( obligation)
276
- }
324
+ Node { ref state, ref mut obligation, .. } if state. get ( ) == NodeState :: Pending =>
325
+ processor. process_obligation ( obligation) ,
277
326
_ => continue
278
327
} ;
279
328
280
- debug ! ( "process_obligations: node {} got result {:?}" ,
281
- index,
282
- result) ;
329
+ debug ! ( "process_obligations: node {} got result {:?}" , index, result) ;
283
330
284
331
match result {
285
332
ProcessResult :: Unchanged => {
@@ -420,13 +467,13 @@ impl<O: ForestObligation> ObligationForest<O> {
420
467
}
421
468
422
469
while let Some ( i) = error_stack. pop ( ) {
423
- let node = & self . nodes [ i] ;
424
-
425
- match node. state . get ( ) {
470
+ match self . nodes [ i] . state . get ( ) {
426
471
NodeState :: Error => continue ,
427
- _ => node . state . set ( NodeState :: Error )
472
+ _ => self . nodes [ i ] . state . set ( NodeState :: Error ) ,
428
473
}
429
474
475
+ let node = & self . nodes [ i] ;
476
+
430
477
error_stack. extend (
431
478
node. parent . iter ( ) . chain ( node. dependents . iter ( ) ) . map ( |x| x. get ( ) )
432
479
) ;
@@ -514,6 +561,7 @@ impl<O: ForestObligation> ObligationForest<O> {
514
561
self . waiting_cache . remove ( self . nodes [ i] . obligation . as_predicate ( ) ) ;
515
562
node_rewrites[ i] = nodes_len;
516
563
dead_nodes += 1 ;
564
+ self . insert_into_error_cache ( i) ;
517
565
}
518
566
NodeState :: OnDfsStack | NodeState :: Success => unreachable ! ( )
519
567
}
@@ -587,12 +635,17 @@ impl<O: ForestObligation> ObligationForest<O> {
587
635
}
588
636
589
637
impl < O > Node < O > {
590
- fn new ( parent : Option < NodeIndex > , obligation : O ) -> Node < O > {
638
+ fn new (
639
+ parent : Option < NodeIndex > ,
640
+ obligation : O ,
641
+ obligation_tree_id : ObligationTreeId
642
+ ) -> Node < O > {
591
643
Node {
592
644
obligation,
593
645
state : Cell :: new ( NodeState :: Pending ) ,
594
646
parent,
595
647
dependents : vec ! [ ] ,
648
+ obligation_tree_id,
596
649
}
597
650
}
598
651
}
0 commit comments