@@ -21,15 +21,16 @@ use std::cell::Cell;
21
21
use std:: collections:: hash_map:: Entry ;
22
22
use std:: fmt:: Debug ;
23
23
use std:: hash;
24
+ use std:: marker:: PhantomData ;
24
25
25
26
mod node_index;
26
27
use self :: node_index:: NodeIndex ;
27
28
28
29
#[ cfg( test) ]
29
30
mod test;
30
31
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 ;
33
34
34
35
fn as_predicate ( & self ) -> & Self :: Predicate ;
35
36
}
@@ -42,9 +43,9 @@ pub trait ObligationProcessor {
42
43
obligation : & mut Self :: Obligation )
43
44
-> Result < Option < Vec < Self :: Obligation > > , Self :: Error > ;
44
45
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 > ;
48
49
}
49
50
50
51
struct SnapshotData {
@@ -66,8 +67,12 @@ pub struct ObligationForest<O: ForestObligation> {
66
67
/// at a higher index than its parent. This is needed by the
67
68
/// backtrace iterator (which uses `split_at`).
68
69
nodes : Vec < Node < O > > ,
70
+ /// A cache of predicates that have been successfully completed.
69
71
done_cache : FnvHashSet < O :: Predicate > ,
72
+ /// An cache of the nodes in `nodes`, indexed by predicate.
70
73
waiting_cache : FnvHashMap < O :: Predicate , NodeIndex > ,
74
+ /// A list of the obligations added in snapshots, to allow
75
+ /// for their removal.
71
76
cache_list : Vec < O :: Predicate > ,
72
77
snapshots : Vec < SnapshotData > ,
73
78
scratch : Option < Vec < usize > > ,
@@ -82,33 +87,33 @@ struct Node<O> {
82
87
obligation : O ,
83
88
state : Cell < NodeState > ,
84
89
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`.
86
96
parent : Option < NodeIndex > ,
87
- dependants : Vec < NodeIndex > ,
88
97
}
89
98
90
99
/// The state of one node in some tree within the forest. This
91
100
/// represents the current state of processing for the obligation (of
92
101
/// type `O`) associated with this node.
102
+ ///
103
+ /// Outside of ObligationForest methods, nodes should be either Pending
104
+ /// or Waiting.
93
105
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
94
106
enum NodeState {
95
- /// Obligation not yet resolved to success or error.
107
+ /// Obligations for which selection had not yet returned a
108
+ /// non-ambiguous result.
96
109
Pending ,
97
110
98
- /// Used before garbage collection
111
+ /// This obligation was selected successfuly, but may or
112
+ /// may not have subobligations.
99
113
Success ,
100
114
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.
112
117
Waiting ,
113
118
114
119
/// This obligation, along with its subobligations, are complete,
@@ -118,6 +123,10 @@ enum NodeState {
118
123
/// This obligation was resolved to an error. Error nodes are
119
124
/// removed from the vector by the compression step.
120
125
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 ,
121
130
}
122
131
123
132
#[ derive( Debug ) ]
@@ -144,7 +153,7 @@ pub struct Error<O, E> {
144
153
pub backtrace : Vec < O > ,
145
154
}
146
155
147
- impl < O : Debug + ForestObligation > ObligationForest < O > {
156
+ impl < O : ForestObligation > ObligationForest < O > {
148
157
pub fn new ( ) -> ObligationForest < O > {
149
158
ObligationForest {
150
159
nodes : vec ! [ ] ,
@@ -210,7 +219,12 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
210
219
debug ! ( "register_obligation_at({:?}, {:?}) - duplicate of {:?}!" ,
211
220
obligation, parent, o. get( ) ) ;
212
221
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
+ }
214
228
}
215
229
}
216
230
Entry :: Vacant ( v) => {
@@ -230,7 +244,6 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
230
244
assert ! ( !self . in_snapshot( ) ) ;
231
245
let mut errors = vec ! [ ] ;
232
246
for index in 0 ..self . nodes . len ( ) {
233
- debug_assert ! ( !self . nodes[ index] . is_popped( ) ) ;
234
247
if let NodeState :: Pending = self . nodes [ index] . state . get ( ) {
235
248
let backtrace = self . error_at ( index) ;
236
249
errors. push ( Error {
@@ -269,8 +282,6 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
269
282
let mut stalled = true ;
270
283
271
284
for index in 0 ..self . nodes . len ( ) {
272
- debug_assert ! ( !self . nodes[ index] . is_popped( ) ) ;
273
-
274
285
debug ! ( "process_obligations: node {} == {:?}" ,
275
286
index,
276
287
self . nodes[ index] ) ;
@@ -327,57 +338,69 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
327
338
}
328
339
}
329
340
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 )
331
346
where P : ObligationProcessor < Obligation =O >
332
347
{
333
348
let mut stack = self . scratch . take ( ) . unwrap ( ) ;
334
349
335
350
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) ;
337
352
}
338
353
339
354
self . scratch = Some ( stack) ;
340
355
}
341
356
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 )
343
359
where P : ObligationProcessor < Obligation =O >
344
360
{
345
361
let node = & self . nodes [ index] ;
346
362
let state = node. state . get ( ) ;
347
363
match state {
348
- NodeState :: InLoop => {
364
+ NodeState :: OnDfsStack => {
349
365
let index =
350
366
stack. iter ( ) . rposition ( |n| * n == index) . unwrap ( ) ;
351
367
// I need a Clone closure
352
368
#[ derive( Clone ) ]
353
369
struct GetObligation < ' a , O : ' a > ( & ' a [ Node < O > ] ) ;
354
370
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 {
357
373
& self . 0 [ * args. 0 ] . obligation
358
374
}
359
375
}
360
376
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 {
362
378
& self . 0 [ * args. 0 ] . obligation
363
379
}
364
380
}
365
381
366
- processor. process_backedge ( stack[ index..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ) ;
382
+ processor. process_backedge ( stack[ index..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ,
383
+ PhantomData ) ;
367
384
}
368
385
NodeState :: Success => {
369
- node. state . set ( NodeState :: InLoop ) ;
386
+ node. state . set ( NodeState :: OnDfsStack ) ;
370
387
stack. push ( index) ;
371
388
if let Some ( parent) = node. parent {
372
- self . visit_node ( stack, processor, parent. get ( ) ) ;
389
+ self . find_cycles_from_node ( stack, processor, parent. get ( ) ) ;
373
390
}
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 ( ) ) ;
376
393
}
377
394
stack. pop ( ) ;
378
395
node. state . set ( NodeState :: Done ) ;
379
396
} ,
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
+ }
381
404
} ;
382
405
}
383
406
@@ -391,7 +414,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
391
414
loop {
392
415
self . nodes [ n] . state . set ( NodeState :: Error ) ;
393
416
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 ( ) ) ) ;
395
418
396
419
// loop to the parent
397
420
match self . nodes [ n] . parent {
@@ -415,15 +438,15 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
415
438
}
416
439
417
440
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 ( ) )
419
442
) ;
420
443
}
421
444
422
445
self . scratch = Some ( error_stack) ;
423
446
trace
424
447
}
425
448
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 .
427
450
fn mark_as_waiting ( & self ) {
428
451
for node in & self . nodes {
429
452
if node. state . get ( ) == NodeState :: Waiting {
@@ -441,7 +464,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
441
464
fn mark_as_waiting_from ( & self , node : & Node < O > ) {
442
465
match node. state . get ( ) {
443
466
NodeState :: Pending | NodeState :: Done => { } ,
444
- NodeState :: Waiting | NodeState :: Error | NodeState :: InLoop => return ,
467
+ NodeState :: Waiting | NodeState :: Error | NodeState :: OnDfsStack => return ,
445
468
NodeState :: Success => {
446
469
node. state . set ( NodeState :: Waiting ) ;
447
470
}
@@ -451,8 +474,8 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
451
474
self . mark_as_waiting_from ( & self . nodes [ parent. get ( ) ] ) ;
452
475
}
453
476
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 ( ) ] ) ;
456
479
}
457
480
}
458
481
@@ -546,12 +569,12 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
546
569
}
547
570
548
571
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 ( ) ] ;
551
574
if new_index >= nodes_len {
552
- node. dependants . swap_remove ( i) ;
575
+ node. dependents . swap_remove ( i) ;
553
576
} else {
554
- node. dependants [ i] = NodeIndex :: new ( new_index) ;
577
+ node. dependents [ i] = NodeIndex :: new ( new_index) ;
555
578
i += 1 ;
556
579
}
557
580
}
@@ -577,14 +600,15 @@ impl<O> Node<O> {
577
600
obligation : obligation,
578
601
parent : parent,
579
602
state : Cell :: new ( NodeState :: Pending ) ,
580
- dependants : vec ! [ ] ,
603
+ dependents : vec ! [ ] ,
581
604
}
582
605
}
583
606
584
607
fn is_popped ( & self ) -> bool {
585
608
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 ! ( )
588
612
}
589
613
}
590
614
}
0 commit comments