@@ -65,6 +65,12 @@ pub enum ProcessResult<O, E> {
6565 Error ( E ) ,
6666}
6767
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+
6874pub struct ObligationForest < O : ForestObligation > {
6975 /// The list of obligations. In between calls to
7076 /// `process_obligations`, this list only contains nodes in the
@@ -79,11 +85,25 @@ pub struct ObligationForest<O: ForestObligation> {
7985 /// at a higher index than its parent. This is needed by the
8086 /// backtrace iterator (which uses `split_at`).
8187 nodes : Vec < Node < O > > ,
88+
8289 /// A cache of predicates that have been successfully completed.
8390 done_cache : FxHashSet < O :: Predicate > ,
91+
8492 /// An cache of the nodes in `nodes`, indexed by predicate.
8593 waiting_cache : FxHashMap < O :: Predicate , NodeIndex > ,
94+
8695 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 > > ,
87107}
88108
89109#[ derive( Debug ) ]
@@ -99,6 +119,9 @@ struct Node<O> {
99119 /// Obligations that depend on this obligation for their
100120 /// completion. They must all be in a non-pending state.
101121 dependents : Vec < NodeIndex > ,
122+
123+ /// Identifier of the obligation tree to which this node belongs.
124+ obligation_tree_id : ObligationTreeId ,
102125}
103126
104127/// The state of one node in some tree within the forest. This
@@ -165,6 +188,8 @@ impl<O: ForestObligation> ObligationForest<O> {
165188 done_cache : FxHashSet ( ) ,
166189 waiting_cache : FxHashMap ( ) ,
167190 scratch : Some ( vec ! [ ] ) ,
191+ obligation_tree_id_generator : ( 0 ..) . map ( |i| ObligationTreeId ( i) ) ,
192+ error_cache : FxHashMap ( ) ,
168193 }
169194 }
170195
@@ -214,9 +239,29 @@ impl<O: ForestObligation> ObligationForest<O> {
214239 Entry :: Vacant ( v) => {
215240 debug ! ( "register_obligation_at({:?}, {:?}) - ok, new index is {}" ,
216241 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+ }
220265 }
221266 }
222267 }
@@ -251,6 +296,15 @@ impl<O: ForestObligation> ObligationForest<O> {
251296 . collect ( )
252297 }
253298
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+
254308 /// Perform a pass through the obligation list. This must
255309 /// be called in a loop until `outcome.stalled` is false.
256310 ///
@@ -264,22 +318,15 @@ impl<O: ForestObligation> ObligationForest<O> {
264318 let mut stalled = true ;
265319
266320 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] ) ;
270322
271323 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) ,
277326 _ => continue
278327 } ;
279328
280- debug ! ( "process_obligations: node {} got result {:?}" ,
281- index,
282- result) ;
329+ debug ! ( "process_obligations: node {} got result {:?}" , index, result) ;
283330
284331 match result {
285332 ProcessResult :: Unchanged => {
@@ -420,13 +467,13 @@ impl<O: ForestObligation> ObligationForest<O> {
420467 }
421468
422469 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 ( ) {
426471 NodeState :: Error => continue ,
427- _ => node . state . set ( NodeState :: Error )
472+ _ => self . nodes [ i ] . state . set ( NodeState :: Error ) ,
428473 }
429474
475+ let node = & self . nodes [ i] ;
476+
430477 error_stack. extend (
431478 node. parent . iter ( ) . chain ( node. dependents . iter ( ) ) . map ( |x| x. get ( ) )
432479 ) ;
@@ -514,6 +561,7 @@ impl<O: ForestObligation> ObligationForest<O> {
514561 self . waiting_cache . remove ( self . nodes [ i] . obligation . as_predicate ( ) ) ;
515562 node_rewrites[ i] = nodes_len;
516563 dead_nodes += 1 ;
564+ self . insert_into_error_cache ( i) ;
517565 }
518566 NodeState :: OnDfsStack | NodeState :: Success => unreachable ! ( )
519567 }
@@ -587,12 +635,17 @@ impl<O: ForestObligation> ObligationForest<O> {
587635}
588636
589637impl < 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 > {
591643 Node {
592644 obligation,
593645 state : Cell :: new ( NodeState :: Pending ) ,
594646 parent,
595647 dependents : vec ! [ ] ,
648+ obligation_tree_id,
596649 }
597650 }
598651}
0 commit comments