1717
1818use fnv:: { FnvHashMap , FnvHashSet } ;
1919
20+ use std:: cell:: Cell ;
2021use std:: collections:: hash_map:: Entry ;
2122use std:: fmt:: Debug ;
2223use std:: hash;
@@ -41,7 +42,9 @@ pub trait ObligationProcessor {
4142 obligation : & mut Self :: Obligation )
4243 -> Result < Option < Vec < Self :: Obligation > > , Self :: Error > ;
4344
44- fn process_backedge ( & mut self , cycle : & [ Self :: Obligation ] ) ;
45+ // FIXME: crazy lifetime troubles
46+ fn process_backedge < I > ( & mut self , cycle : I )
47+ where I : Clone + Iterator < Item =* const Self :: Obligation > ;
4548}
4649
4750struct SnapshotData {
@@ -77,7 +80,7 @@ pub struct Snapshot {
7780#[ derive( Debug ) ]
7881struct Node < O > {
7982 obligation : O ,
80- state : NodeState ,
83+ state : Cell < NodeState > ,
8184
8285 // these both go *in the same direction*.
8386 parent : Option < NodeIndex > ,
@@ -87,14 +90,17 @@ struct Node<O> {
8790/// The state of one node in some tree within the forest. This
8891/// represents the current state of processing for the obligation (of
8992/// type `O`) associated with this node.
90- #[ derive( Debug , PartialEq , Eq ) ]
93+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
9194enum NodeState {
9295 /// Obligation not yet resolved to success or error.
9396 Pending ,
9497
9598 /// Used before garbage collection
9699 Success ,
97100
101+ /// Used in DFS loops
102+ InLoop ,
103+
98104 /// Obligation resolved to success; `num_incomplete_children`
99105 /// indicates the number of children still in an "incomplete"
100106 /// state. Incomplete means that either the child is still
@@ -225,7 +231,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
225231 let mut errors = vec ! [ ] ;
226232 for index in 0 ..self . nodes . len ( ) {
227233 debug_assert ! ( !self . nodes[ index] . is_popped( ) ) ;
228- if let NodeState :: Pending = self . nodes [ index] . state {
234+ if let NodeState :: Pending = self . nodes [ index] . state . get ( ) {
229235 let backtrace = self . error_at ( index) ;
230236 errors. push ( Error {
231237 error : error. clone ( ) ,
@@ -244,7 +250,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
244250 {
245251 self . nodes
246252 . iter ( )
247- . filter ( |n| n. state == NodeState :: Pending )
253+ . filter ( |n| n. state . get ( ) == NodeState :: Pending )
248254 . map ( |n| n. obligation . clone ( ) )
249255 . collect ( )
250256 }
@@ -270,7 +276,9 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
270276 self . nodes[ index] ) ;
271277
272278 let result = match self . nodes [ index] {
273- Node { state : NodeState :: Pending , ref mut obligation, .. } => {
279+ Node { state : ref _state, ref mut obligation, .. }
280+ if _state. get ( ) == NodeState :: Pending =>
281+ {
274282 processor. process_obligation ( obligation)
275283 }
276284 _ => continue
@@ -292,7 +300,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
292300 Some ( NodeIndex :: new ( index) ) ) ;
293301 }
294302
295- self . nodes [ index] . state = NodeState :: Success ;
303+ self . nodes [ index] . state . set ( NodeState :: Success ) ;
296304 }
297305 Err ( err) => {
298306 let backtrace = self . error_at ( index) ;
@@ -319,29 +327,69 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
319327 }
320328 }
321329
322- pub fn process_cycles < P > ( & mut self , _processor : & mut P )
330+ pub fn process_cycles < P > ( & mut self , processor : & mut P )
323331 where P : ObligationProcessor < Obligation =O >
324332 {
325- // TODO: implement
326- for node in & mut self . nodes {
327- if node. state == NodeState :: Success {
328- node. state = NodeState :: Done ;
329- }
333+ let mut stack = self . scratch . take ( ) . unwrap ( ) ;
334+
335+ for node in 0 ..self . nodes . len ( ) {
336+ self . visit_node ( & mut stack, processor, node) ;
330337 }
338+
339+ self . scratch = Some ( stack) ;
340+ }
341+
342+ fn visit_node < P > ( & self , stack : & mut Vec < usize > , processor : & mut P , index : usize )
343+ where P : ObligationProcessor < Obligation =O >
344+ {
345+ let node = & self . nodes [ index] ;
346+ let state = node. state . get ( ) ;
347+ match state {
348+ NodeState :: InLoop => {
349+ let index =
350+ stack. iter ( ) . rposition ( |n| * n == index) . unwrap ( ) ;
351+ // I need a Clone closure
352+ #[ derive( Clone ) ]
353+ struct GetObligation < ' a , O : ' a > ( & ' a [ Node < O > ] ) ;
354+ impl < ' a , ' b , O > FnOnce < ( & ' b usize , ) > for GetObligation < ' a , O > {
355+ type Output = * const O ;
356+ extern "rust-call" fn call_once ( self , args : ( & ' b usize , ) ) -> * const O {
357+ & self . 0 [ * args. 0 ] . obligation
358+ }
359+ }
360+ impl < ' a , ' b , O > FnMut < ( & ' b usize , ) > for GetObligation < ' a , O > {
361+ extern "rust-call" fn call_mut ( & mut self , args : ( & ' b usize , ) ) -> * const O {
362+ & self . 0 [ * args. 0 ] . obligation
363+ }
364+ }
365+
366+ processor. process_backedge ( stack[ index..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ) ;
367+ }
368+ NodeState :: Success => {
369+ node. state . set ( NodeState :: InLoop ) ;
370+ stack. push ( index) ;
371+ if let Some ( parent) = node. parent {
372+ self . visit_node ( stack, processor, parent. get ( ) ) ;
373+ }
374+ for dependant in & node. dependants {
375+ self . visit_node ( stack, processor, dependant. get ( ) ) ;
376+ }
377+ stack. pop ( ) ;
378+ node. state . set ( NodeState :: Done ) ;
379+ } ,
380+ _ => return
381+ } ;
331382 }
332383
333384 /// Returns a vector of obligations for `p` and all of its
334385 /// ancestors, putting them into the error state in the process.
335- /// The fact that the root is now marked as an error is used by
336- /// `inherit_error` above to propagate the error state to the
337- /// remainder of the tree.
338386 fn error_at ( & mut self , p : usize ) -> Vec < O > {
339387 let mut error_stack = self . scratch . take ( ) . unwrap ( ) ;
340388 let mut trace = vec ! [ ] ;
341389
342390 let mut n = p;
343391 loop {
344- self . nodes [ n] . state = NodeState :: Error ;
392+ self . nodes [ n] . state . set ( NodeState :: Error ) ;
345393 trace. push ( self . nodes [ n] . obligation . clone ( ) ) ;
346394 error_stack. extend ( self . nodes [ n] . dependants . iter ( ) . map ( |x| x. get ( ) ) ) ;
347395
@@ -359,12 +407,13 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
359407 None => break
360408 } ;
361409
362- match self . nodes [ i] . state {
410+ let node = & self . nodes [ i] ;
411+
412+ match node. state . get ( ) {
363413 NodeState :: Error => continue ,
364- ref mut s => * s = NodeState :: Error
414+ _ => node . state . set ( NodeState :: Error )
365415 }
366416
367- let node = & self . nodes [ i] ;
368417 error_stack. extend (
369418 node. dependants . iter ( ) . cloned ( ) . chain ( node. parent ) . map ( |x| x. get ( ) )
370419 ) ;
@@ -374,41 +423,37 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
374423 trace
375424 }
376425
377- fn mark_as_waiting ( & mut self ) {
378- for node in & mut self . nodes {
379- if node. state == NodeState :: Waiting {
380- node. state = NodeState :: Success ;
426+ /// Marks all nodes that depend on a pending node as "waiting".
427+ fn mark_as_waiting ( & self ) {
428+ for node in & self . nodes {
429+ if node. state . get ( ) == NodeState :: Waiting {
430+ node. state . set ( NodeState :: Success ) ;
381431 }
382432 }
383433
384- let mut undone_stack = self . scratch . take ( ) . unwrap ( ) ;
385- undone_stack. extend (
386- self . nodes . iter ( ) . enumerate ( )
387- . filter ( |& ( _i, n) | n. state == NodeState :: Pending )
388- . map ( |( i, _n) | i) ) ;
389-
390- loop {
391- // non-standard `while let` to bypass #6393
392- let i = match undone_stack. pop ( ) {
393- Some ( i) => i,
394- None => break
395- } ;
434+ for node in & self . nodes {
435+ if node. state . get ( ) == NodeState :: Pending {
436+ self . mark_as_waiting_from ( node)
437+ }
438+ }
439+ }
396440
397- match self . nodes [ i ] . state {
398- NodeState :: Pending | NodeState :: Done => { } ,
399- NodeState :: Waiting | NodeState :: Error => continue ,
400- ref mut s @ NodeState :: Success => {
401- * s = NodeState :: Waiting ;
402- }
441+ fn mark_as_waiting_from ( & self , node : & Node < O > ) {
442+ match node . state . get ( ) {
443+ NodeState :: Pending | NodeState :: Done => { } ,
444+ NodeState :: Waiting | NodeState :: Error | NodeState :: InLoop => return ,
445+ NodeState :: Success => {
446+ node . state . set ( NodeState :: Waiting ) ;
403447 }
448+ }
404449
405- let node = & self . nodes [ i] ;
406- undone_stack. extend (
407- node. dependants . iter ( ) . cloned ( ) . chain ( node. parent ) . map ( |x| x. get ( ) )
408- ) ;
450+ if let Some ( parent) = node. parent {
451+ self . mark_as_waiting_from ( & self . nodes [ parent. get ( ) ] ) ;
409452 }
410453
411- self . scratch = Some ( undone_stack) ;
454+ for dependant in & node. dependants {
455+ self . mark_as_waiting_from ( & self . nodes [ dependant. get ( ) ] ) ;
456+ }
412457 }
413458
414459 /// Compresses the vector, removing all popped nodes. This adjusts
@@ -433,12 +478,22 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
433478 // self.nodes[i - dead_nodes..i] are all dead
434479 // self.nodes[i..] are unchanged
435480 for i in 0 ..self . nodes . len ( ) {
436- if let NodeState :: Done = self . nodes [ i] . state {
437- self . done_cache . insert ( self . nodes [ i] . obligation . as_predicate ( ) . clone ( ) ) ;
481+ match self . nodes [ i] . state . get ( ) {
482+ NodeState :: Done => {
483+ self . waiting_cache . remove ( self . nodes [ i] . obligation . as_predicate ( ) ) ;
484+ // FIXME(HashMap): why can't I get my key back?
485+ self . done_cache . insert ( self . nodes [ i] . obligation . as_predicate ( ) . clone ( ) ) ;
486+ }
487+ NodeState :: Error => {
488+ // We *intentionally* remove the node from the cache at this point. Otherwise
489+ // tests must come up with a different type on every type error they
490+ // check against.
491+ self . waiting_cache . remove ( self . nodes [ i] . obligation . as_predicate ( ) ) ;
492+ }
493+ _ => { }
438494 }
439495
440496 if self . nodes [ i] . is_popped ( ) {
441- self . waiting_cache . remove ( self . nodes [ i] . obligation . as_predicate ( ) ) ;
442497 node_rewrites[ i] = nodes_len;
443498 dead_nodes += 1 ;
444499 } else {
@@ -461,7 +516,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
461516 let successful = ( 0 ..dead_nodes)
462517 . map ( |_| self . nodes . pop ( ) . unwrap ( ) )
463518 . flat_map ( |node| {
464- match node. state {
519+ match node. state . get ( ) {
465520 NodeState :: Error => None ,
466521 NodeState :: Done => Some ( node. obligation ) ,
467522 _ => unreachable ! ( )
@@ -521,15 +576,15 @@ impl<O> Node<O> {
521576 Node {
522577 obligation : obligation,
523578 parent : parent,
524- state : NodeState :: Pending ,
579+ state : Cell :: new ( NodeState :: Pending ) ,
525580 dependants : vec ! [ ] ,
526581 }
527582 }
528583
529584 fn is_popped ( & self ) -> bool {
530- match self . state {
585+ match self . state . get ( ) {
531586 NodeState :: Pending | NodeState :: Success | NodeState :: Waiting => false ,
532- NodeState :: Error | NodeState :: Done => true ,
587+ NodeState :: Error | NodeState :: Done | NodeState :: InLoop => true ,
533588 }
534589 }
535590}
0 commit comments