75
75
use crate :: fx:: { FxHashMap , FxHashSet } ;
76
76
77
77
use std:: cell:: { Cell , RefCell } ;
78
+ use std:: cmp:: Ordering ;
78
79
use std:: collections:: hash_map:: Entry ;
80
+ use std:: collections:: BinaryHeap ;
79
81
use std:: fmt:: Debug ;
80
82
use std:: hash;
81
83
use std:: marker:: PhantomData ;
@@ -87,8 +89,11 @@ mod graphviz;
87
89
mod tests;
88
90
89
91
pub trait ForestObligation : Clone + Debug {
92
+ /// A key used to avoid evaluating the same obligation twice
90
93
type CacheKey : Clone + hash:: Hash + Eq + Debug ;
94
+ /// The variable type used in the obligation when it could not yet be fulfilled
91
95
type Variable : Clone + hash:: Hash + Eq + Debug ;
96
+ /// A type which tracks which variables has been unified
92
97
type WatcherOffset ;
93
98
94
99
/// Converts this `ForestObligation` suitable for use as a cache key.
@@ -97,6 +102,8 @@ pub trait ForestObligation: Clone + Debug {
97
102
/// (e.g. success for error) for the other obligation
98
103
fn as_cache_key ( & self ) -> Self :: CacheKey ;
99
104
105
+ /// Returns which variables this obligation is currently stalled on. If the slice is empty then
106
+ /// the variables stalled on are unknown.
100
107
fn stalled_on ( & self ) -> & [ Self :: Variable ] ;
101
108
}
102
109
@@ -124,7 +131,7 @@ pub trait ObligationProcessor {
124
131
fn unblocked (
125
132
& self ,
126
133
offset : & <Self :: Obligation as ForestObligation >:: WatcherOffset ,
127
- f : impl FnMut ( <Self :: Obligation as ForestObligation >:: Variable ) -> bool ,
134
+ f : impl FnMut ( <Self :: Obligation as ForestObligation >:: Variable ) ,
128
135
) ;
129
136
fn register ( & self ) -> <Self :: Obligation as ForestObligation >:: WatcherOffset ;
130
137
fn deregister ( & self , offset : <Self :: Obligation as ForestObligation >:: WatcherOffset ) ;
@@ -157,9 +164,16 @@ pub struct ObligationForest<O: ForestObligation> {
157
164
/// this list only contains nodes in the `Pending` or `Waiting` state.
158
165
nodes : Vec < Node < O > > ,
159
166
160
- /// Nodes must be processed in the order that they were added which this list keeps track of.
167
+ /// Nodes must be processed in the order that they were added so we give each node a unique,
168
+ /// number allowing them to be ordered when processing them.
169
+ node_number : u32 ,
170
+
171
+ /// Stores the indices of the nodes currently in the pending state
161
172
pending_nodes : Vec < NodeIndex > ,
173
+
174
+ /// Stores the indices of the nodes currently in the success or waiting states
162
175
success_or_waiting_nodes : Vec < NodeIndex > ,
176
+ /// Stores the indices of the nodes currently in the error or done states
163
177
error_or_done_nodes : RefCell < Vec < NodeIndex > > ,
164
178
165
179
/// Nodes that have been removed and are ready to be reused
@@ -171,7 +185,6 @@ pub struct ObligationForest<O: ForestObligation> {
171
185
active_cache : FxHashMap < O :: CacheKey , Option < NodeIndex > > ,
172
186
173
187
obligation_tree_id_generator : ObligationTreeIdGenerator ,
174
- node_number : u32 ,
175
188
176
189
/// Per tree error cache. This is used to deduplicate errors,
177
190
/// which is necessary to avoid trait resolution overflow in
@@ -182,18 +195,25 @@ pub struct ObligationForest<O: ForestObligation> {
182
195
/// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780
183
196
error_cache : FxHashMap < ObligationTreeId , FxHashSet < O :: CacheKey > > ,
184
197
198
+ /// Stores which nodes would be unblocked once `O::Variable` is unified
185
199
stalled_on : FxHashMap < O :: Variable , Vec < NodeIndex > > ,
186
- unblocked : std:: collections:: BinaryHeap < Unblocked > ,
200
+ /// Stores the node indices that are unblocked and should be processed at the next opportunity
201
+ unblocked : BinaryHeap < Unblocked > ,
202
+ /// Stores nodes which should be processed on the next iteration since the variables they are
203
+ /// actually blocked on are unknown
187
204
check_next : Vec < NodeIndex > ,
205
+ /// The offset that this `ObligationForest` has registered. Should be de-registered before
206
+ /// dropping this forest.
188
207
offset : Option < O :: WatcherOffset > ,
189
208
}
190
209
210
+ /// Helper struct for use with `BinaryHeap` to process nodes in the order that they were added to
211
+ /// the forest
191
212
struct Unblocked {
192
- index : usize ,
213
+ index : NodeIndex ,
193
214
order : u32 ,
194
215
}
195
216
196
- use std:: cmp:: Ordering ;
197
217
impl PartialEq for Unblocked {
198
218
fn eq ( & self , other : & Self ) -> bool {
199
219
self . order == other. order
@@ -216,11 +236,14 @@ struct Node<O: ForestObligation> {
216
236
obligation : O ,
217
237
state : Cell < NodeState > ,
218
238
239
+ /// A predicate (and its key) can changed during processing. If it does we need to register the
240
+ /// old predicate so that we can remove or mark it as done if this node errors or is done.
219
241
alternative_predicates : Vec < O :: CacheKey > ,
220
242
221
243
/// Obligations that depend on this obligation for their completion. They
222
244
/// must all be in a non-pending state.
223
245
dependents : Vec < NodeIndex > ,
246
+ /// Obligations that this obligation depends on for their completion.
224
247
reverse_dependents : Vec < NodeIndex > ,
225
248
226
249
/// If true, `dependents[0]` points to a "parent" node, which requires
@@ -257,6 +280,7 @@ where
257
280
}
258
281
}
259
282
283
+ /// Initializes a node, reusing the existing allocations
260
284
fn init (
261
285
& mut self ,
262
286
parent : Option < NodeIndex > ,
@@ -473,12 +497,16 @@ impl<O: ForestObligation> ObligationForest<O> {
473
497
. get ( & obligation_tree_id)
474
498
. map ( |errors| errors. contains ( & obligation. as_cache_key ( ) ) )
475
499
. unwrap_or ( false ) ;
500
+ // Retrieves a fresh number for the new node so that each node are processed in the
501
+ // order that they were created
476
502
let node_number = self . node_number ;
477
503
self . node_number += 1 ;
478
504
479
505
if already_failed {
480
506
Err ( ( ) )
481
507
} else {
508
+ // If we have a dead node we can reuse it and it's associated allocations,
509
+ // otherwise allocate a new node
482
510
let new_index = if let Some ( new_index) = self . dead_nodes . pop ( ) {
483
511
let node = & mut self . nodes [ new_index] ;
484
512
node. init ( parent, obligation, obligation_tree_id, node_number) ;
@@ -549,11 +577,6 @@ impl<O: ForestObligation> ObligationForest<O> {
549
577
if self . offset . is_none ( ) {
550
578
self . offset = Some ( processor. register ( ) ) ;
551
579
}
552
- warn ! (
553
- "Begin process {}, pending: {}" ,
554
- self . nodes. len( ) ,
555
- self . nodes. iter( ) . filter( |n| n. state. get( ) == NodeState :: Pending ) . count( )
556
- ) ;
557
580
let mut errors = vec ! [ ] ;
558
581
let mut stalled = true ;
559
582
@@ -577,6 +600,8 @@ impl<O: ForestObligation> ObligationForest<O> {
577
600
if node. state . get ( ) != NodeState :: Pending {
578
601
continue ;
579
602
}
603
+
604
+ // Any variables we were stalled on are now resolved so remove the watches
580
605
for var in node. obligation . stalled_on ( ) {
581
606
match self . stalled_on . entry ( var. clone ( ) ) {
582
607
Entry :: Vacant ( _) => ( ) ,
@@ -607,18 +632,22 @@ impl<O: ForestObligation> ObligationForest<O> {
607
632
let node = & mut self . nodes [ index] ;
608
633
match result {
609
634
ProcessResult :: Unchanged => {
610
- for var in node. obligation . stalled_on ( ) {
611
- self . stalled_on
612
- . entry ( var. clone ( ) )
613
- . or_insert_with ( || {
614
- processor. watch_variable ( var. clone ( ) ) ;
615
- Vec :: new ( )
616
- } )
617
- . push ( index) ;
618
- }
619
-
620
- if node. obligation . stalled_on ( ) . is_empty ( ) {
635
+ // We stalled but the variables that caused it are unknown so we run
636
+ // `index` again at the next opportunity
637
+ let stalled_on = node. obligation . stalled_on ( ) ;
638
+ if stalled_on. is_empty ( ) {
621
639
self . check_next . push ( index) ;
640
+ } else {
641
+ // Register every variable that we stal
642
+ for var in stalled_on {
643
+ self . stalled_on
644
+ . entry ( var. clone ( ) )
645
+ . or_insert_with ( || {
646
+ processor. watch_variable ( var. clone ( ) ) ;
647
+ Vec :: new ( )
648
+ } )
649
+ . push ( index) ;
650
+ }
622
651
}
623
652
// No change in state.
624
653
}
@@ -646,7 +675,6 @@ impl<O: ForestObligation> ObligationForest<O> {
646
675
}
647
676
648
677
if stalled {
649
- warn ! ( "Stalled {}" , self . nodes. len( ) ) ;
650
678
// There's no need to perform marking, cycle processing and compression when nothing
651
679
// changed.
652
680
return Outcome {
@@ -655,13 +683,9 @@ impl<O: ForestObligation> ObligationForest<O> {
655
683
} ;
656
684
}
657
685
658
- warn ! ( "Compressing {}" , self . nodes. len( ) ) ;
659
686
self . mark_successes ( ) ;
660
687
self . process_cycles ( processor) ;
661
688
let completed = self . compress ( do_completed) ;
662
- warn ! ( "Compressed {}" , self . nodes. len( ) ) ;
663
-
664
- warn ! ( "Stalled on: {:?}" , self . stalled_on. keys( ) . collect:: <Vec <_>>( ) ) ;
665
689
666
690
Outcome { completed, errors }
667
691
}
@@ -678,19 +702,16 @@ impl<O: ForestObligation> ObligationForest<O> {
678
702
processor. unblocked ( self . offset . as_ref ( ) . unwrap ( ) , |var| {
679
703
if let Some ( unblocked_nodes) = stalled_on. remove ( & var) {
680
704
for node_index in unblocked_nodes {
705
+ let node = & nodes[ node_index] ;
681
706
debug_assert ! (
682
- nodes [ node_index ] . state. get( ) == NodeState :: Pending ,
707
+ node . state. get( ) == NodeState :: Pending ,
683
708
"Unblocking non-pending2: {:?}" ,
684
- nodes [ node_index ] . obligation
709
+ node . obligation
685
710
) ;
686
- unblocked. push ( Unblocked {
687
- index : node_index,
688
- order : nodes[ node_index] . node_number ,
689
- } ) ;
711
+ unblocked. push ( Unblocked { index : node_index, order : node. node_number } ) ;
690
712
}
691
713
temp. push ( var) ;
692
714
}
693
- true
694
715
} ) ;
695
716
for var in temp {
696
717
processor. unwatch_variable ( var) ;
@@ -848,6 +869,7 @@ impl<O: ForestObligation> ObligationForest<O> {
848
869
fn compress ( & mut self , do_completed : DoCompleted ) -> Option < Vec < O > > {
849
870
let mut removed_done_obligations: Vec < O > = vec ! [ ] ;
850
871
872
+ // Compress the forest by removing any nodes marked as error or done
851
873
let mut error_or_done_nodes = mem:: take ( self . error_or_done_nodes . get_mut ( ) ) ;
852
874
for & index in & error_or_done_nodes {
853
875
let node = & mut self . nodes [ index] ;
0 commit comments