@@ -21,15 +21,16 @@ use std::cell::Cell;
2121use std:: collections:: hash_map:: Entry ;
2222use std:: fmt:: Debug ;
2323use std:: hash;
24+ use std:: marker:: PhantomData ;
2425
2526mod node_index;
2627use self :: node_index:: NodeIndex ;
2728
2829#[ cfg( test) ]
2930mod test;
3031
31- pub trait ForestObligation : Clone {
32- type Predicate : Clone + hash:: Hash + Eq + :: std :: fmt :: Debug ;
32+ pub trait ForestObligation : Clone + Debug {
33+ type Predicate : Clone + hash:: Hash + Eq + Debug ;
3334
3435 fn as_predicate ( & self ) -> & Self :: Predicate ;
3536}
@@ -42,9 +43,9 @@ pub trait ObligationProcessor {
4243 obligation : & mut Self :: Obligation )
4344 -> Result < Option < Vec < Self :: Obligation > > , Self :: Error > ;
4445
45- // FIXME: crazy lifetime troubles
46- fn process_backedge < I > ( & mut self , cycle : I )
47- where I : Clone + Iterator < Item =* const Self :: Obligation > ;
46+ fn process_backedge < ' c , I > ( & mut self , cycle : I ,
47+ _marker : PhantomData < & ' c Self :: Obligation > )
48+ where I : Clone + Iterator < Item =& ' c Self :: Obligation > ;
4849}
4950
5051struct SnapshotData {
@@ -66,8 +67,12 @@ pub struct ObligationForest<O: ForestObligation> {
6667 /// at a higher index than its parent. This is needed by the
6768 /// backtrace iterator (which uses `split_at`).
6869 nodes : Vec < Node < O > > ,
70+ /// A cache of predicates that have been successfully completed.
6971 done_cache : FnvHashSet < O :: Predicate > ,
72+ /// An cache of the nodes in `nodes`, indexed by predicate.
7073 waiting_cache : FnvHashMap < O :: Predicate , NodeIndex > ,
74+ /// A list of the obligations added in snapshots, to allow
75+ /// for their removal.
7176 cache_list : Vec < O :: Predicate > ,
7277 snapshots : Vec < SnapshotData > ,
7378 scratch : Option < Vec < usize > > ,
@@ -82,33 +87,33 @@ struct Node<O> {
8287 obligation : O ,
8388 state : Cell < NodeState > ,
8489
85- // these both go *in the same direction*.
90+ /// Obligations that depend on this obligation for their
91+ /// completion. They must all be in a non-pending state.
92+ dependents : Vec < NodeIndex > ,
93+ /// The parent of a node - the original obligation of
94+ /// which it is a subobligation. Except for error reporting,
95+ /// this is just another member of `dependents`.
8696 parent : Option < NodeIndex > ,
87- dependants : Vec < NodeIndex > ,
8897}
8998
9099/// The state of one node in some tree within the forest. This
91100/// represents the current state of processing for the obligation (of
92101/// type `O`) associated with this node.
102+ ///
103+ /// Outside of ObligationForest methods, nodes should be either Pending
104+ /// or Waiting.
93105#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
94106enum NodeState {
95- /// Obligation not yet resolved to success or error.
107+ /// Obligations for which selection had not yet returned a
108+ /// non-ambiguous result.
96109 Pending ,
97110
98- /// Used before garbage collection
111+ /// This obligation was selected successfuly, but may or
112+ /// may not have subobligations.
99113 Success ,
100114
101- /// Used in DFS loops
102- InLoop ,
103-
104- /// Obligation resolved to success; `num_incomplete_children`
105- /// indicates the number of children still in an "incomplete"
106- /// state. Incomplete means that either the child is still
107- /// pending, or it has children which are incomplete. (Basically,
108- /// there is pending work somewhere in the subtree of the child.)
109- ///
110- /// Once all children have completed, success nodes are removed
111- /// from the vector by the compression step.
115+ /// This obligation was selected sucessfully, but it has
116+ /// a pending subobligation.
112117 Waiting ,
113118
114119 /// This obligation, along with its subobligations, are complete,
@@ -118,6 +123,10 @@ enum NodeState {
118123 /// This obligation was resolved to an error. Error nodes are
119124 /// removed from the vector by the compression step.
120125 Error ,
126+
127+ /// This is a temporary state used in DFS loops to detect cycles,
128+ /// it should not exist outside of these DFSes.
129+ OnDfsStack ,
121130}
122131
123132#[ derive( Debug ) ]
@@ -144,7 +153,7 @@ pub struct Error<O, E> {
144153 pub backtrace : Vec < O > ,
145154}
146155
147- impl < O : Debug + ForestObligation > ObligationForest < O > {
156+ impl < O : ForestObligation > ObligationForest < O > {
148157 pub fn new ( ) -> ObligationForest < O > {
149158 ObligationForest {
150159 nodes : vec ! [ ] ,
@@ -210,7 +219,12 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
210219 debug ! ( "register_obligation_at({:?}, {:?}) - duplicate of {:?}!" ,
211220 obligation, parent, o. get( ) ) ;
212221 if let Some ( parent) = parent {
213- self . nodes [ o. get ( ) . get ( ) ] . dependants . push ( parent) ;
222+ if self . nodes [ o. get ( ) . get ( ) ] . dependents . contains ( & parent) {
223+ debug ! ( "register_obligation_at({:?}, {:?}) - duplicate subobligation" ,
224+ obligation, parent) ;
225+ } else {
226+ self . nodes [ o. get ( ) . get ( ) ] . dependents . push ( parent) ;
227+ }
214228 }
215229 }
216230 Entry :: Vacant ( v) => {
@@ -230,7 +244,6 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
230244 assert ! ( !self . in_snapshot( ) ) ;
231245 let mut errors = vec ! [ ] ;
232246 for index in 0 ..self . nodes . len ( ) {
233- debug_assert ! ( !self . nodes[ index] . is_popped( ) ) ;
234247 if let NodeState :: Pending = self . nodes [ index] . state . get ( ) {
235248 let backtrace = self . error_at ( index) ;
236249 errors. push ( Error {
@@ -269,8 +282,6 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
269282 let mut stalled = true ;
270283
271284 for index in 0 ..self . nodes . len ( ) {
272- debug_assert ! ( !self . nodes[ index] . is_popped( ) ) ;
273-
274285 debug ! ( "process_obligations: node {} == {:?}" ,
275286 index,
276287 self . nodes[ index] ) ;
@@ -327,57 +338,69 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
327338 }
328339 }
329340
330- pub fn process_cycles < P > ( & mut self , processor : & mut P )
341+ /// Mark all NodeState::Success nodes as NodeState::Done and
342+ /// report all cycles between them. This should be called
343+ /// after `mark_as_waiting` marks all nodes with pending
344+ /// subobligations as NodeState::Waiting.
345+ fn process_cycles < P > ( & mut self , processor : & mut P )
331346 where P : ObligationProcessor < Obligation =O >
332347 {
333348 let mut stack = self . scratch . take ( ) . unwrap ( ) ;
334349
335350 for node in 0 ..self . nodes . len ( ) {
336- self . visit_node ( & mut stack, processor, node) ;
351+ self . find_cycles_from_node ( & mut stack, processor, node) ;
337352 }
338353
339354 self . scratch = Some ( stack) ;
340355 }
341356
342- fn visit_node < P > ( & self , stack : & mut Vec < usize > , processor : & mut P , index : usize )
357+ fn find_cycles_from_node < P > ( & self , stack : & mut Vec < usize > ,
358+ processor : & mut P , index : usize )
343359 where P : ObligationProcessor < Obligation =O >
344360 {
345361 let node = & self . nodes [ index] ;
346362 let state = node. state . get ( ) ;
347363 match state {
348- NodeState :: InLoop => {
364+ NodeState :: OnDfsStack => {
349365 let index =
350366 stack. iter ( ) . rposition ( |n| * n == index) . unwrap ( ) ;
351367 // I need a Clone closure
352368 #[ derive( Clone ) ]
353369 struct GetObligation < ' a , O : ' a > ( & ' a [ Node < O > ] ) ;
354370 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 {
371+ type Output = & ' a O ;
372+ extern "rust-call" fn call_once ( self , args : ( & ' b usize , ) ) -> & ' a O {
357373 & self . 0 [ * args. 0 ] . obligation
358374 }
359375 }
360376 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 {
377+ extern "rust-call" fn call_mut ( & mut self , args : ( & ' b usize , ) ) -> & ' a O {
362378 & self . 0 [ * args. 0 ] . obligation
363379 }
364380 }
365381
366- processor. process_backedge ( stack[ index..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ) ;
382+ processor. process_backedge ( stack[ index..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ,
383+ PhantomData ) ;
367384 }
368385 NodeState :: Success => {
369- node. state . set ( NodeState :: InLoop ) ;
386+ node. state . set ( NodeState :: OnDfsStack ) ;
370387 stack. push ( index) ;
371388 if let Some ( parent) = node. parent {
372- self . visit_node ( stack, processor, parent. get ( ) ) ;
389+ self . find_cycles_from_node ( stack, processor, parent. get ( ) ) ;
373390 }
374- for dependant in & node. dependants {
375- self . visit_node ( stack, processor, dependant . get ( ) ) ;
391+ for dependent in & node. dependents {
392+ self . find_cycles_from_node ( stack, processor, dependent . get ( ) ) ;
376393 }
377394 stack. pop ( ) ;
378395 node. state . set ( NodeState :: Done ) ;
379396 } ,
380- _ => return
397+ NodeState :: Waiting | NodeState :: Pending => {
398+ // this node is still reachable from some pending node. We
399+ // will get to it when they are all processed.
400+ }
401+ NodeState :: Done | NodeState :: Error => {
402+ // already processed that node
403+ }
381404 } ;
382405 }
383406
@@ -391,7 +414,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
391414 loop {
392415 self . nodes [ n] . state . set ( NodeState :: Error ) ;
393416 trace. push ( self . nodes [ n] . obligation . clone ( ) ) ;
394- error_stack. extend ( self . nodes [ n] . dependants . iter ( ) . map ( |x| x. get ( ) ) ) ;
417+ error_stack. extend ( self . nodes [ n] . dependents . iter ( ) . map ( |x| x. get ( ) ) ) ;
395418
396419 // loop to the parent
397420 match self . nodes [ n] . parent {
@@ -415,15 +438,15 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
415438 }
416439
417440 error_stack. extend (
418- node. dependants . iter ( ) . cloned ( ) . chain ( node. parent ) . map ( |x| x. get ( ) )
441+ node. dependents . iter ( ) . cloned ( ) . chain ( node. parent ) . map ( |x| x. get ( ) )
419442 ) ;
420443 }
421444
422445 self . scratch = Some ( error_stack) ;
423446 trace
424447 }
425448
426- /// Marks all nodes that depend on a pending node as "waiting" .
449+ /// Marks all nodes that depend on a pending node as NodeState;:Waiting .
427450 fn mark_as_waiting ( & self ) {
428451 for node in & self . nodes {
429452 if node. state . get ( ) == NodeState :: Waiting {
@@ -441,7 +464,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
441464 fn mark_as_waiting_from ( & self , node : & Node < O > ) {
442465 match node. state . get ( ) {
443466 NodeState :: Pending | NodeState :: Done => { } ,
444- NodeState :: Waiting | NodeState :: Error | NodeState :: InLoop => return ,
467+ NodeState :: Waiting | NodeState :: Error | NodeState :: OnDfsStack => return ,
445468 NodeState :: Success => {
446469 node. state . set ( NodeState :: Waiting ) ;
447470 }
@@ -451,8 +474,8 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
451474 self . mark_as_waiting_from ( & self . nodes [ parent. get ( ) ] ) ;
452475 }
453476
454- for dependant in & node. dependants {
455- self . mark_as_waiting_from ( & self . nodes [ dependant . get ( ) ] ) ;
477+ for dependent in & node. dependents {
478+ self . mark_as_waiting_from ( & self . nodes [ dependent . get ( ) ] ) ;
456479 }
457480 }
458481
@@ -546,12 +569,12 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
546569 }
547570
548571 let mut i = 0 ;
549- while i < node. dependants . len ( ) {
550- let new_index = node_rewrites[ node. dependants [ i] . get ( ) ] ;
572+ while i < node. dependents . len ( ) {
573+ let new_index = node_rewrites[ node. dependents [ i] . get ( ) ] ;
551574 if new_index >= nodes_len {
552- node. dependants . swap_remove ( i) ;
575+ node. dependents . swap_remove ( i) ;
553576 } else {
554- node. dependants [ i] = NodeIndex :: new ( new_index) ;
577+ node. dependents [ i] = NodeIndex :: new ( new_index) ;
555578 i += 1 ;
556579 }
557580 }
@@ -577,14 +600,15 @@ impl<O> Node<O> {
577600 obligation : obligation,
578601 parent : parent,
579602 state : Cell :: new ( NodeState :: Pending ) ,
580- dependants : vec ! [ ] ,
603+ dependents : vec ! [ ] ,
581604 }
582605 }
583606
584607 fn is_popped ( & self ) -> bool {
585608 match self . state . get ( ) {
586- NodeState :: Pending | NodeState :: Success | NodeState :: Waiting => false ,
587- NodeState :: Error | NodeState :: Done | NodeState :: InLoop => true ,
609+ NodeState :: Pending | NodeState :: Waiting => false ,
610+ NodeState :: Error | NodeState :: Done => true ,
611+ NodeState :: OnDfsStack | NodeState :: Success => unreachable ! ( )
588612 }
589613 }
590614}
0 commit comments