88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ //! The `ObligationForest` is a utility data structure used in trait
12+ //! matching to track the set of outstanding obligations (those not
13+ //! yet resolved to success or error). It also tracks the "backtrace"
14+ //! of each pending obligation (why we are trying to figure this out
15+ //! in the first place). See README.md for a general overview of how
16+ //! to use this class.
17+
1118use std:: fmt:: Debug ;
1219use std:: mem;
1320
@@ -17,6 +24,18 @@ mod node_index;
1724mod test;
1825
1926pub struct ObligationForest < O > {
27+ /// The list of obligations. In between calls to
28+ /// `process_obligations`, this list only contains nodes in the
29+ /// `Pending` or `Success` state (with a non-zero number of
30+ /// incomplete children). During processing, some of those nodes
31+ /// may be changed to the error state, or we may find that they
32+ /// are completed (That is, `num_incomplete_children` drops to 0).
33+ /// At the end of processing, those nodes will be removed by a
34+ /// call to `compress`.
35+ ///
36+ /// At all times we maintain the invariant that every node appears
37+ /// at a higher index than its parent. This is needed by the
38+ /// backtrace iterator (which uses `split_at`).
2039 nodes : Vec < Node < O > > ,
2140 snapshots : Vec < usize >
2241}
@@ -33,28 +52,44 @@ struct Node<O> {
3352 root : NodeIndex , // points to the root, which may be the current node
3453}
3554
55+ /// The state of one node in some tree within the forest. This
56+ /// represents the current state of processing for the obligation (of
57+ /// type `O`) associated with this node.
3658#[ derive( Debug ) ]
3759enum NodeState < O > {
38- Leaf { obligation : O } ,
39- Success { obligation : O , num_children : usize } ,
60+ /// Obligation not yet resolved to success or error.
61+ Pending { obligation : O } ,
62+
63+ /// Obligation resolved to success; `num_incomplete_children`
64+ /// indicates the number of children still in an "incomplete"
65+ /// state. Incomplete means that either the child is still
66+ /// pending, or it has children which are incomplete. (Basically,
67+ /// there is pending work somewhere in the subtree of the child.)
68+ ///
69+ /// Once all children have completed, success nodes are removed
70+ /// from the vector by the compression step.
71+ Success { obligation : O , num_incomplete_children : usize } ,
72+
73+ /// This obligation was resolved to an error. Error nodes are
74+ /// removed from the vector by the compression step.
4075 Error ,
4176}
4277
4378#[ derive( Debug ) ]
4479pub struct Outcome < O , E > {
4580 /// Obligations that were completely evaluated, including all
4681 /// (transitive) subobligations.
47- pub successful : Vec < O > ,
82+ pub completed : Vec < O > ,
4883
4984 /// Backtrace of obligations that were found to be in error.
5085 pub errors : Vec < Error < O , E > > ,
5186
5287 /// If true, then we saw no successful obligations, which means
5388 /// there is no point in further iteration. This is based on the
54- /// assumption that `Err` and `Ok(None)` results do not affect
55- /// environmental inference state. (Note that if we invoke
56- /// `process_obligations` with no pending obligations, stalled
57- /// will be true.)
89+ /// assumption that when trait matching returns `Err` or
90+ /// `Ok(None)`, those results do not affect environmental
91+ /// inference state. (Note that if we invoke `process_obligations`
92+ /// with no pending obligations, stalled will be true.)
5893 pub stalled : bool ,
5994}
6095
@@ -90,13 +125,15 @@ impl<O: Debug> ObligationForest<O> {
90125 }
91126
92127 pub fn rollback_snapshot ( & mut self , snapshot : Snapshot ) {
93- // check that we are obeying stack discipline
128+ // Check that we are obeying stack discipline.
94129 assert_eq ! ( snapshot. len, self . snapshots. len( ) ) ;
95130 let nodes_len = self . snapshots . pop ( ) . unwrap ( ) ;
96131
97- // the only action permitted while in a snapshot is to push new roots
132+ // The only action permitted while in a snapshot is to push
133+ // new root obligations. Because no processing will have been
134+ // done, those roots should still be in the pending state.
98135 debug_assert ! ( self . nodes[ nodes_len..] . iter( ) . all( |n| match n. state {
99- NodeState :: Leaf { .. } => true ,
136+ NodeState :: Pending { .. } => true ,
100137 _ => false ,
101138 } ) ) ;
102139
@@ -116,12 +153,15 @@ impl<O: Debug> ObligationForest<O> {
116153 }
117154
118155 /// Convert all remaining obligations to the given error.
156+ ///
157+ /// This cannot be done during a snapshot.
119158 pub fn to_errors < E : Clone > ( & mut self , error : E ) -> Vec < Error < O , E > > {
159+ assert ! ( !self . in_snapshot( ) ) ;
120160 let mut errors = vec ! [ ] ;
121161 for index in 0 ..self . nodes . len ( ) {
122162 debug_assert ! ( !self . nodes[ index] . is_popped( ) ) ;
123163 self . inherit_error ( index) ;
124- if let NodeState :: Leaf { .. } = self . nodes [ index] . state {
164+ if let NodeState :: Pending { .. } = self . nodes [ index] . state {
125165 let backtrace = self . backtrace ( index) ;
126166 errors. push ( Error { error : error. clone ( ) , backtrace : backtrace } ) ;
127167 }
@@ -131,11 +171,11 @@ impl<O: Debug> ObligationForest<O> {
131171 errors
132172 }
133173
134- /// Convert all remaining obligations to the given error .
174+ /// Returns the set of obligations that are in a pending state .
135175 pub fn pending_obligations ( & self ) -> Vec < O > where O : Clone {
136176 self . nodes . iter ( )
137177 . filter_map ( |n| match n. state {
138- NodeState :: Leaf { ref obligation } => Some ( obligation) ,
178+ NodeState :: Pending { ref obligation } => Some ( obligation) ,
139179 _ => None ,
140180 } )
141181 . cloned ( )
@@ -174,9 +214,11 @@ impl<O: Debug> ObligationForest<O> {
174214 let ( prefix, suffix) = self . nodes . split_at_mut ( index) ;
175215 let backtrace = Backtrace :: new ( prefix, parent) ;
176216 match suffix[ 0 ] . state {
177- NodeState :: Error => continue ,
178- NodeState :: Success { .. } => continue ,
179- NodeState :: Leaf { ref mut obligation } => action ( obligation, backtrace) ,
217+ NodeState :: Error |
218+ NodeState :: Success { .. } =>
219+ continue ,
220+ NodeState :: Pending { ref mut obligation } =>
221+ action ( obligation, backtrace) ,
180222 }
181223 } ;
182224
@@ -204,7 +246,7 @@ impl<O: Debug> ObligationForest<O> {
204246 debug ! ( "process_obligations: complete" ) ;
205247
206248 Outcome {
207- successful : successful_obligations,
249+ completed : successful_obligations,
208250 errors : errors,
209251 stalled : stalled,
210252 }
@@ -219,9 +261,9 @@ impl<O: Debug> ObligationForest<O> {
219261 fn success ( & mut self , index : usize , children : Vec < O > ) {
220262 debug ! ( "success(index={}, children={:?})" , index, children) ;
221263
222- let num_children = children. len ( ) ;
264+ let num_incomplete_children = children. len ( ) ;
223265
224- if num_children == 0 {
266+ if num_incomplete_children == 0 {
225267 // if there is no work left to be done, decrement parent's ref count
226268 self . update_parent ( index) ;
227269 } else {
@@ -233,13 +275,14 @@ impl<O: Debug> ObligationForest<O> {
233275 . map ( |o| Node :: new ( root_index, Some ( node_index) , o) ) ) ;
234276 }
235277
236- // change state from `Leaf ` to `Success`, temporarily swapping in `Error`
278+ // change state from `Pending ` to `Success`, temporarily swapping in `Error`
237279 let state = mem:: replace ( & mut self . nodes [ index] . state , NodeState :: Error ) ;
238280 self . nodes [ index] . state = match state {
239- NodeState :: Leaf { obligation } =>
281+ NodeState :: Pending { obligation } =>
240282 NodeState :: Success { obligation : obligation,
241- num_children : num_children } ,
242- NodeState :: Success { .. } | NodeState :: Error =>
283+ num_incomplete_children : num_incomplete_children } ,
284+ NodeState :: Success { .. } |
285+ NodeState :: Error =>
243286 unreachable ! ( )
244287 } ;
245288 }
@@ -251,9 +294,9 @@ impl<O: Debug> ObligationForest<O> {
251294 if let Some ( parent) = self . nodes [ child] . parent {
252295 let parent = parent. get ( ) ;
253296 match self . nodes [ parent] . state {
254- NodeState :: Success { ref mut num_children , .. } => {
255- * num_children -= 1 ;
256- if * num_children > 0 {
297+ NodeState :: Success { ref mut num_incomplete_children , .. } => {
298+ * num_incomplete_children -= 1 ;
299+ if * num_incomplete_children > 0 {
257300 return ;
258301 }
259302 }
@@ -263,8 +306,10 @@ impl<O: Debug> ObligationForest<O> {
263306 }
264307 }
265308
266- /// If the root of `child` is in an error error, places `child`
267- /// into an error state.
309+ /// If the root of `child` is in an error state, places `child`
310+ /// into an error state. This is used during processing so that we
311+ /// skip the remaining obligations from a tree once some other
312+ /// node in the tree is found to be in error.
268313 fn inherit_error ( & mut self , child : usize ) {
269314 let root = self . nodes [ child] . root . get ( ) ;
270315 if let NodeState :: Error = self . nodes [ root] . state {
@@ -274,12 +319,15 @@ impl<O: Debug> ObligationForest<O> {
274319
275320 /// Returns a vector of obligations for `p` and all of its
276321 /// ancestors, putting them into the error state in the process.
322+ /// The fact that the root is now marked as an error is used by
323+ /// `inherit_error` above to propagate the error state to the
324+ /// remainder of the tree.
277325 fn backtrace ( & mut self , mut p : usize ) -> Vec < O > {
278326 let mut trace = vec ! [ ] ;
279327 loop {
280328 let state = mem:: replace ( & mut self . nodes [ p] . state , NodeState :: Error ) ;
281329 match state {
282- NodeState :: Leaf { obligation } |
330+ NodeState :: Pending { obligation } |
283331 NodeState :: Success { obligation, .. } => {
284332 trace. push ( obligation) ;
285333 }
@@ -338,9 +386,9 @@ impl<O: Debug> ObligationForest<O> {
338386 ( 0 .. dead) . map ( |_| self . nodes . pop ( ) . unwrap ( ) )
339387 . flat_map ( |node| match node. state {
340388 NodeState :: Error => None ,
341- NodeState :: Leaf { .. } => unreachable ! ( ) ,
342- NodeState :: Success { obligation, num_children } => {
343- assert_eq ! ( num_children , 0 ) ;
389+ NodeState :: Pending { .. } => unreachable ! ( ) ,
390+ NodeState :: Success { obligation, num_incomplete_children } => {
391+ assert_eq ! ( num_incomplete_children , 0 ) ;
344392 Some ( obligation)
345393 }
346394 } )
@@ -365,15 +413,15 @@ impl<O> Node<O> {
365413 fn new ( root : NodeIndex , parent : Option < NodeIndex > , obligation : O ) -> Node < O > {
366414 Node {
367415 parent : parent,
368- state : NodeState :: Leaf { obligation : obligation } ,
416+ state : NodeState :: Pending { obligation : obligation } ,
369417 root : root
370418 }
371419 }
372420
373421 fn is_popped ( & self ) -> bool {
374422 match self . state {
375- NodeState :: Leaf { .. } => false ,
376- NodeState :: Success { num_children , .. } => num_children == 0 ,
423+ NodeState :: Pending { .. } => false ,
424+ NodeState :: Success { num_incomplete_children , .. } => num_incomplete_children == 0 ,
377425 NodeState :: Error => true ,
378426 }
379427 }
@@ -399,7 +447,8 @@ impl<'b, O> Iterator for Backtrace<'b, O> {
399447 if let Some ( p) = self . pointer {
400448 self . pointer = self . nodes [ p. get ( ) ] . parent ;
401449 match self . nodes [ p. get ( ) ] . state {
402- NodeState :: Leaf { ref obligation } | NodeState :: Success { ref obligation, .. } => {
450+ NodeState :: Pending { ref obligation } |
451+ NodeState :: Success { ref obligation, .. } => {
403452 Some ( obligation)
404453 }
405454 NodeState :: Error => {
0 commit comments