@@ -302,6 +302,12 @@ enum ContinueTraversal {
302302 SkipSelfAndChildren ,
303303}
304304
305+ #[ derive( Clone , Copy ) ]
306+ pub enum ChildrenVisitMode {
307+ VisitChildrenOfAccessed ,
308+ SkipChildrenOfAccessed ,
309+ }
310+
305311/// Stack of nodes left to explore in a tree traversal.
306312struct TreeVisitorStack < NodeContinue , NodeApp , ErrHandler > {
307313 /// Identifier of the original access.
@@ -316,9 +322,9 @@ struct TreeVisitorStack<NodeContinue, NodeApp, ErrHandler> {
316322 /// Mutable state of the visit: the tags left to handle.
317323 /// Every tag pushed should eventually be handled,
318324 /// and the precise order is relevant for diagnostics.
319- /// Since the traversal is bottom-up, we need to remember
320- /// whether we're here initially (false) or after visiting all
321- /// children (true). The bool indicates this.
325+ /// Since the traversal is piecewise bottom-up, we need to
326+ /// remember whether we're here initially (false) or after
327+ /// visiting all children (true). The bool indicates this.
322328 stack : Vec < ( UniIndex , AccessRelatedness , bool ) > ,
323329}
324330
@@ -362,15 +368,15 @@ where
362368 & mut self ,
363369 this : & mut TreeVisitor < ' _ > ,
364370 accessed_node : UniIndex ,
365- push_children_of_accessed : bool ,
371+ visit_children : ChildrenVisitMode ,
366372 ) -> Result < ( ) , OutErr > {
367373 assert ! ( self . stack. is_empty( ) ) ;
368374 // First, handle accessed node. A bunch of things need to
369375 // be handled differently here compared to the further parents
370376 // of `accesssed_node`.
371377 {
372378 self . propagate_at ( this, accessed_node, AccessRelatedness :: This ) ?;
373- if push_children_of_accessed {
379+ if matches ! ( visit_children , ChildrenVisitMode :: VisitChildrenOfAccessed ) {
374380 let accessed_node = this. nodes . get ( accessed_node) . unwrap ( ) ;
375381 for & child in accessed_node. children . iter ( ) . rev ( ) {
376382 self . stack . push ( ( child, AccessRelatedness :: AncestorAccess , false ) ) ;
@@ -437,19 +443,34 @@ where
437443}
438444
439445impl < ' tree > TreeVisitor < ' tree > {
440- // Applies `f_propagate` to every vertex of the tree bottom-up in the following order: first
446+ // Applies `f_propagate` to every vertex of the tree in a piecewise bottom-up way: First, visit
441447 // all ancestors of `start` (starting with `start` itself), then children of `start`, then the rest,
442- // always going bottom-up.
448+ // going bottom-up in each of these two "pieces" / sections .
443449 // This ensures that errors are triggered in the following order
444450 // - first invalid accesses with insufficient permissions, closest to the accessed node first,
445451 // - then protector violations, bottom-up, starting with the children of the accessed node, and then
446452 // going upwards and outwards.
453+ // The following graphic visualizes it, with numbers indicating visitation order and `start` being
454+ // the node that is visited first ("1"):
455+ //
456+ // 3
457+ // |
458+ // 2
459+ // /|\
460+ // / | \
461+ // 7 1 8
462+ // / \
463+ // 4 6
464+ // |
465+ // 5
447466 //
448467 // `f_propagate` should follow the following format: for a given `Node` it updates its
449468 // `Permission` depending on the position relative to `start` (given by an
450469 // `AccessRelatedness`).
451- // `f_continue` is called before on foreign nodes, and describes whether to continue
452- // with the subtree at that node.
470+ // `f_continue` is called earlier on foreign nodes, and describes whether to even start
471+ // visiting the subtree at that node. If it e.g. returns `SkipSelfAndChildren` on node 6
472+ // above, then nodes 5 _and_ 6 would not be visited by `f_propagate`. It is not used for
473+ // notes having a child access (nodes 1, 2, 3).
453474 fn traverse_this_parents_children_other < InnErr , OutErr > (
454475 mut self ,
455476 start : BorTag ,
@@ -463,7 +484,11 @@ impl<'tree> TreeVisitor<'tree> {
463484 // undergoing a child access. Also pushes the children and the other
464485 // cousin nodes (i.e. all nodes undergoing a foreign access) to the stack
465486 // to be processed later.
466- stack. go_upwards_from_accessed ( & mut self , start_idx, true ) ?;
487+ stack. go_upwards_from_accessed (
488+ & mut self ,
489+ start_idx,
490+ ChildrenVisitMode :: VisitChildrenOfAccessed ,
491+ ) ?;
467492 // Now visit all the foreign nodes we remembered earlier.
468493 // For this we go bottom-up, but also allow f_continue to skip entire
469494 // subtrees from being visited if it would be a NOP.
@@ -483,7 +508,11 @@ impl<'tree> TreeVisitor<'tree> {
483508 // Visits the accessed node itself, and all its parents, i.e. all nodes
484509 // undergoing a child access. Also pushes the other cousin nodes to the
485510 // stack, but not the children of the accessed node.
486- stack. go_upwards_from_accessed ( & mut self , start_idx, false ) ?;
511+ stack. go_upwards_from_accessed (
512+ & mut self ,
513+ start_idx,
514+ ChildrenVisitMode :: SkipChildrenOfAccessed ,
515+ ) ?;
487516 // Now visit all the foreign nodes we remembered earlier.
488517 // For this we go bottom-up, but also allow f_continue to skip entire
489518 // subtrees from being visited if it would be a NOP.
0 commit comments