1010
1111use std:: assert_matches:: debug_assert_matches;
1212use std:: fmt:: Debug ;
13+ use std:: marker:: PhantomData ;
1314use std:: ops:: Range ;
1415
1516use rustc_index:: { Idx , IndexSlice , IndexVec } ;
@@ -49,16 +50,21 @@ pub trait Annotation: Debug + Copy {
4950}
5051
5152/// An accumulator for annotations.
52- pub trait Annotations < N : Idx , S : Idx , A : Annotation > {
53- fn new ( & self , element : N ) -> A ;
54- fn annotate_scc ( & mut self , scc : S , annotation : A ) ;
53+ pub trait Annotations < N : Idx > {
54+ type Ann : Annotation ;
55+ type SccIdx : Idx + Ord ;
56+
57+ fn new ( & self , element : N ) -> Self :: Ann ;
58+ fn annotate_scc ( & mut self , scc : Self :: SccIdx , annotation : Self :: Ann ) ;
5559}
5660
5761/// The nil annotation accumulator, which does nothing.
58- impl < N : Idx , S : Idx > Annotations < N , S , ( ) > for ( ) {
59- fn new ( & self , _element : N ) -> ( ) {
60- ( )
61- }
62+ struct NoAnnotations < S : Idx + Ord > ( PhantomData < S > ) ;
63+
64+ impl < N : Idx , S : Idx + Ord > Annotations < N > for NoAnnotations < S > {
65+ type SccIdx = S ;
66+ type Ann = ( ) ;
67+ fn new ( & self , _element : N ) { }
6268 fn annotate_scc ( & mut self , _scc : S , _annotation : ( ) ) { }
6369}
6470
@@ -112,13 +118,13 @@ struct SccData<S: Idx> {
112118impl < N : Idx , S : Idx + Ord > Sccs < N , S > {
113119 /// Compute SCCs without annotations.
114120 pub fn new ( graph : & impl Successors < Node = N > ) -> Self {
115- Self :: new_with_annotation ( graph, & mut ( ) )
121+ Self :: new_with_annotation ( graph, & mut NoAnnotations ( PhantomData :: < S > ) )
116122 }
117123
118124 /// Compute SCCs and annotate them with a user-supplied annotation
119- pub fn new_with_annotation < A : Annotation , AA : Annotations < N , S , A > > (
125+ pub fn new_with_annotation < A : Annotations < N , SccIdx = S > > (
120126 graph : & impl Successors < Node = N > ,
121- annotations : & mut AA ,
127+ annotations : & mut A ,
122128 ) -> Self {
123129 SccsConstruction :: construct ( graph, annotations)
124130 }
@@ -141,13 +147,7 @@ impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
141147 pub fn all_sccs ( & self ) -> impl Iterator < Item = S > + ' static {
142148 ( 0 ..self . scc_data . len ( ) ) . map ( S :: new)
143149 }
144- /*
145- /// Returns an iterator over the SCC annotations in the graph
146- /// The order is the same as `all_sccs()`, dependency order.
147- pub fn all_annotations(&self, annotations: &A) -> impl Iterator<Item = (S, A)> + use<'_, N, S, A> {
148- self.all_sccs().map(|scc| (scc, self.annotation(scc)))
149- }
150- */
150+
151151 /// Returns the SCC to which a node `r` belongs.
152152 pub fn scc ( & self , r : N ) -> S {
153153 self . scc_indices [ r]
@@ -223,19 +223,17 @@ impl<S: Idx> SccData<S> {
223223 }
224224}
225225
226- struct SccsConstruction < ' c , ' a , G , S , A , AA >
226+ struct SccsConstruction < ' c , ' a , G , A >
227227where
228228 G : DirectedGraph + Successors ,
229- S : Idx ,
230- A : Annotation ,
231- AA : Annotations < G :: Node , S , A > ,
229+ A : Annotations < G :: Node > ,
232230{
233231 graph : & ' c G ,
234232
235233 /// The state of each node; used during walk to record the stack
236234 /// and after walk to record what cycle each node ended up being
237235 /// in.
238- node_states : IndexVec < G :: Node , NodeState < G :: Node , S , A > > ,
236+ node_states : IndexVec < G :: Node , NodeState < G :: Node , A :: SccIdx , A :: Ann > > ,
239237
240238 /// The stack of nodes that we are visiting as part of the DFS.
241239 node_stack : Vec < G :: Node > ,
@@ -244,21 +242,21 @@ where
244242 /// position in this stack, and when we encounter a successor SCC,
245243 /// we push it on the stack. When we complete an SCC, we can pop
246244 /// everything off the stack that was found along the way.
247- successors_stack : Vec < S > ,
245+ successors_stack : Vec < A :: SccIdx > ,
248246
249247 /// A set used to strip duplicates. As we accumulate successors
250248 /// into the successors_stack, we sometimes get duplicate entries.
251249 /// We use this set to remove those -- we also keep its storage
252250 /// around between successors to amortize memory allocation costs.
253- duplicate_set : FxHashSet < S > ,
251+ duplicate_set : FxHashSet < A :: SccIdx > ,
254252
255- scc_data : SccData < S > ,
253+ scc_data : SccData < A :: SccIdx > ,
256254
257- annotations : & ' a mut AA ,
255+ annotations : & ' a mut A ,
258256}
259257
260258#[ derive( Copy , Clone , Debug ) ]
261- enum NodeState < N , S , A > {
259+ enum NodeState < N , S , A : Annotation > {
262260 /// This node has not yet been visited as part of the DFS.
263261 ///
264262 /// After SCC construction is complete, this state ought to be
@@ -289,7 +287,7 @@ enum NodeState<N, S, A> {
289287
290288/// The state of walking a given node.
291289#[ derive( Copy , Clone , Debug ) ]
292- enum WalkReturn < S , A > {
290+ enum WalkReturn < S , A : Annotation > {
293291 /// The walk found a cycle, but the entire component is not known to have
294292 /// been fully walked yet. We only know the minimum depth of this
295293 /// component in a minimum spanning tree of the graph. This component
@@ -302,12 +300,10 @@ enum WalkReturn<S, A> {
302300 Complete { scc_index : S , annotation : A } ,
303301}
304302
305- impl < ' c , ' a , G , S , A , AA > SccsConstruction < ' c , ' a , G , S , A , AA >
303+ impl < ' c , ' a , G , A > SccsConstruction < ' c , ' a , G , A >
306304where
307305 G : DirectedGraph + Successors ,
308- S : Idx ,
309- A : Annotation ,
310- AA : Annotations < G :: Node , S , A > ,
306+ A : Annotations < G :: Node > ,
311307{
312308 /// Identifies SCCs in the graph `G` and computes the resulting
313309 /// DAG. This uses a variant of [Tarjan's
@@ -323,7 +319,7 @@ where
323319 /// Additionally, we keep track of a current annotation of the SCC.
324320 ///
325321 /// [wikipedia]: https://bit.ly/2EZIx84
326- fn construct ( graph : & ' c G , annotations : & ' a mut AA ) -> Sccs < G :: Node , S > {
322+ fn construct ( graph : & ' c G , annotations : & ' a mut A ) -> Sccs < G :: Node , A :: SccIdx > {
327323 let num_nodes = graph. num_nodes ( ) ;
328324
329325 let mut this = Self {
@@ -349,7 +345,7 @@ where
349345 Sccs { scc_indices, scc_data : this. scc_data }
350346 }
351347
352- fn start_walk_from ( & mut self , node : G :: Node ) -> WalkReturn < S , A > {
348+ fn start_walk_from ( & mut self , node : G :: Node ) -> WalkReturn < A :: SccIdx , A :: Ann > {
353349 self . inspect_node ( node) . unwrap_or_else ( || self . walk_unvisited_node ( node) )
354350 }
355351
@@ -365,7 +361,7 @@ where
365361 /// Otherwise, we are looking at a node that has already been
366362 /// completely visited. We therefore return `WalkReturn::Complete`
367363 /// with its associated SCC index.
368- fn inspect_node ( & mut self , node : G :: Node ) -> Option < WalkReturn < S , A > > {
364+ fn inspect_node ( & mut self , node : G :: Node ) -> Option < WalkReturn < A :: SccIdx , A :: Ann > > {
369365 Some ( match self . find_state ( node) {
370366 NodeState :: InCycle { scc_index, annotation } => {
371367 WalkReturn :: Complete { scc_index, annotation }
@@ -388,7 +384,7 @@ where
388384 /// of `r2` (and updates `r` to reflect current result). This is
389385 /// basically the "find" part of a standard union-find algorithm
390386 /// (with path compression).
391- fn find_state ( & mut self , mut node : G :: Node ) -> NodeState < G :: Node , S , A > {
387+ fn find_state ( & mut self , mut node : G :: Node ) -> NodeState < G :: Node , A :: SccIdx , A :: Ann > {
392388 // To avoid recursion we temporarily reuse the `parent` of each
393389 // InCycleWith link to encode a downwards link while compressing
394390 // the path. After we have found the root or deepest node being
@@ -511,7 +507,7 @@ where
511507 /// caller decide avoids mutual recursion between the two methods and allows
512508 /// us to maintain an allocated stack for nodes on the path between calls.
513509 #[ instrument( skip( self , initial) , level = "trace" ) ]
514- fn walk_unvisited_node ( & mut self , initial : G :: Node ) -> WalkReturn < S , A > {
510+ fn walk_unvisited_node ( & mut self , initial : G :: Node ) -> WalkReturn < A :: SccIdx , A :: Ann > {
515511 trace ! ( "Walk unvisited node: {initial:?}" ) ;
516512 struct VisitingNodeFrame < G : DirectedGraph , Successors , A > {
517513 node : G :: Node ,
0 commit comments