rustc_data_structures/graph/scc/
mod.rs

1//! Routine to compute the strongly connected components (SCCs) of a graph.
2//!
3//! Also computes as the resulting DAG if each SCC is replaced with a
4//! node in the graph. This uses [Tarjan's algorithm](
5//! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
6//! that completes in *O*(*n*) time.
7//! Optionally, also annotate the SCC nodes with some commutative data.
8//! Typical examples would include: minimum element in SCC, maximum element
9//! reachable from it, etc.
10
11use std::assert_matches::debug_assert_matches;
12use std::fmt::Debug;
13use std::marker::PhantomData;
14use std::ops::Range;
15
16use rustc_index::{Idx, IndexSlice, IndexVec};
17use tracing::{debug, instrument, trace};
18
19use crate::fx::FxHashSet;
20use crate::graph::vec_graph::VecGraph;
21use crate::graph::{DirectedGraph, NumEdges, Successors};
22
23#[cfg(test)]
24mod tests;
25
26/// An annotation for an SCC. This can be a representative,
27/// the max/min element of the SCC, or all of the above.
28///
29/// Concretely, the both merge operations must commute, e.g. where `merge`
30/// is `merge_scc` and `merge_reached`: `a.merge(b) == b.merge(a)`
31///
32/// In general, what you want is probably always min/max according
33/// to some ordering, potentially with side constraints (min x such
34/// that P holds).
35pub trait Annotation: Debug + Copy {
36    /// Merge two existing annotations into one during
37    /// path compression.o
38    fn merge_scc(self, other: Self) -> Self;
39
40    /// Merge a successor into this annotation.
41    fn merge_reached(self, other: Self) -> Self;
42
43    fn update_scc(&mut self, other: Self) {
44        *self = self.merge_scc(other)
45    }
46
47    fn update_reachable(&mut self, other: Self) {
48        *self = self.merge_reached(other)
49    }
50}
51
52/// An accumulator for annotations.
53pub 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);
59}
60
61/// The nil annotation accumulator, which does nothing.
62struct NoAnnotations<S: Idx + Ord>(PhantomData<S>);
63
64impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
65    type SccIdx = S;
66    type Ann = ();
67    fn new(&self, _element: N) {}
68    fn annotate_scc(&mut self, _scc: S, _annotation: ()) {}
69}
70
71/// The empty annotation, which does nothing.
72impl Annotation for () {
73    fn merge_reached(self, _other: Self) -> Self {
74        ()
75    }
76    fn merge_scc(self, _other: Self) -> Self {
77        ()
78    }
79}
80
81/// Strongly connected components (SCC) of a graph. The type `N` is
82/// the index type for the graph nodes and `S` is the index type for
83/// the SCCs. We can map from each node to the SCC that it
84/// participates in, and we also have the successors of each SCC.
85pub struct Sccs<N: Idx, S: Idx> {
86    /// For each node, what is the SCC index of the SCC to which it
87    /// belongs.
88    scc_indices: IndexVec<N, S>,
89
90    /// Data about all the SCCs.
91    scc_data: SccData<S>,
92}
93
94/// Information about an invidividual SCC node.
95struct SccDetails {
96    /// For this SCC, the range of `all_successors` where its
97    /// successors can be found.
98    range: Range<usize>,
99}
100
101// The name of this struct should discourage you from making it public and leaking
102// its representation. This message was left here by one who came before you,
103// who learnt the hard way that making even small changes in representation
104// is difficult when it's publicly inspectable.
105//
106// Obey the law of Demeter!
107struct SccData<S: Idx> {
108    /// Maps SCC indices to their metadata, including
109    /// offsets into `all_successors`.
110    scc_details: IndexVec<S, SccDetails>,
111
112    /// Contains the successors for all the Sccs, concatenated. The
113    /// range of indices corresponding to a given SCC is found in its
114    /// `scc_details.range`.
115    all_successors: Vec<S>,
116}
117
118impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
119    /// Compute SCCs without annotations.
120    pub fn new(graph: &impl Successors<Node = N>) -> Self {
121        Self::new_with_annotation(graph, &mut NoAnnotations(PhantomData::<S>))
122    }
123
124    /// Compute SCCs and annotate them with a user-supplied annotation
125    pub fn new_with_annotation<A: Annotations<N, SccIdx = S>>(
126        graph: &impl Successors<Node = N>,
127        annotations: &mut A,
128    ) -> Self {
129        SccsConstruction::construct(graph, annotations)
130    }
131
132    pub fn scc_indices(&self) -> &IndexSlice<N, S> {
133        &self.scc_indices
134    }
135
136    /// Returns the number of SCCs in the graph.
137    pub fn num_sccs(&self) -> usize {
138        self.scc_data.len()
139    }
140
141    /// Returns an iterator over the SCCs in the graph.
142    ///
143    /// The SCCs will be iterated in **dependency order** (or **post order**),
144    /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after.
145    /// This is convenient when the edges represent dependencies: when you visit
146    /// `S1`, the value for `S2` will already have been computed.
147    pub fn all_sccs(&self) -> impl Iterator<Item = S> + 'static {
148        (0..self.scc_data.len()).map(S::new)
149    }
150
151    /// Returns the SCC to which a node `r` belongs.
152    pub fn scc(&self, r: N) -> S {
153        self.scc_indices[r]
154    }
155
156    /// Returns the successors of the given SCC.
157    pub fn successors(&self, scc: S) -> &[S] {
158        self.scc_data.successors(scc)
159    }
160
161    /// Construct the reverse graph of the SCC graph.
162    pub fn reverse(&self) -> VecGraph<S> {
163        VecGraph::new(
164            self.num_sccs(),
165            self.all_sccs()
166                .flat_map(|source| {
167                    self.successors(source).iter().map(move |&target| (target, source))
168                })
169                .collect(),
170        )
171    }
172}
173
174impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> {
175    type Node = S;
176
177    fn num_nodes(&self) -> usize {
178        self.num_sccs()
179    }
180}
181
182impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> {
183    fn num_edges(&self) -> usize {
184        self.scc_data.all_successors.len()
185    }
186}
187
188impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
189    fn successors(&self, node: S) -> impl Iterator<Item = Self::Node> {
190        self.successors(node).iter().cloned()
191    }
192}
193
194impl<S: Idx> SccData<S> {
195    /// Number of SCCs,
196    fn len(&self) -> usize {
197        self.scc_details.len()
198    }
199
200    /// Returns the successors of the given SCC.
201    fn successors(&self, scc: S) -> &[S] {
202        &self.all_successors[self.scc_details[scc].range.clone()]
203    }
204
205    /// Creates a new SCC with `successors` as its successors and
206    /// returns the resulting index.
207    fn create_scc(&mut self, successors: impl IntoIterator<Item = S>) -> S {
208        // Store the successors on `scc_successors_vec`, remembering
209        // the range of indices.
210        let all_successors_start = self.all_successors.len();
211        self.all_successors.extend(successors);
212        let all_successors_end = self.all_successors.len();
213
214        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:214",
                        "rustc_data_structures::graph::scc",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(214u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("create_scc({0:?}) successors={1:?}",
                                                    self.len(),
                                                    &self.all_successors[all_successors_start..all_successors_end])
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(
215            "create_scc({:?}) successors={:?}",
216            self.len(),
217            &self.all_successors[all_successors_start..all_successors_end],
218        );
219
220        let range = all_successors_start..all_successors_end;
221        let metadata = SccDetails { range };
222        self.scc_details.push(metadata)
223    }
224}
225
226struct SccsConstruction<'c, 'a, G, A>
227where
228    G: DirectedGraph + Successors,
229    A: Annotations<G::Node>,
230{
231    graph: &'c G,
232
233    /// The state of each node; used during walk to record the stack
234    /// and after walk to record what cycle each node ended up being
235    /// in.
236    node_states: IndexVec<G::Node, NodeState<G::Node, A::SccIdx, A::Ann>>,
237
238    /// The stack of nodes that we are visiting as part of the DFS.
239    node_stack: Vec<G::Node>,
240
241    /// The stack of successors: as we visit a node, we mark our
242    /// position in this stack, and when we encounter a successor SCC,
243    /// we push it on the stack. When we complete an SCC, we can pop
244    /// everything off the stack that was found along the way.
245    successors_stack: Vec<A::SccIdx>,
246
247    /// A set used to strip duplicates. As we accumulate successors
248    /// into the successors_stack, we sometimes get duplicate entries.
249    /// We use this set to remove those -- we also keep its storage
250    /// around between successors to amortize memory allocation costs.
251    duplicate_set: FxHashSet<A::SccIdx>,
252
253    scc_data: SccData<A::SccIdx>,
254
255    annotations: &'a mut A,
256}
257
258#[derive(#[automatically_derived]
impl<N: ::core::marker::Copy, S: ::core::marker::Copy,
    A: ::core::marker::Copy + Annotation> ::core::marker::Copy for
    NodeState<N, S, A> {
}Copy, #[automatically_derived]
impl<N: ::core::clone::Clone, S: ::core::clone::Clone,
    A: ::core::clone::Clone + Annotation> ::core::clone::Clone for
    NodeState<N, S, A> {
    #[inline]
    fn clone(&self) -> NodeState<N, S, A> {
        match self {
            NodeState::NotVisited => NodeState::NotVisited,
            NodeState::BeingVisited { depth: __self_0, annotation: __self_1 }
                =>
                NodeState::BeingVisited {
                    depth: ::core::clone::Clone::clone(__self_0),
                    annotation: ::core::clone::Clone::clone(__self_1),
                },
            NodeState::InCycle { scc_index: __self_0, annotation: __self_1 }
                =>
                NodeState::InCycle {
                    scc_index: ::core::clone::Clone::clone(__self_0),
                    annotation: ::core::clone::Clone::clone(__self_1),
                },
            NodeState::InCycleWith { parent: __self_0 } =>
                NodeState::InCycleWith {
                    parent: ::core::clone::Clone::clone(__self_0),
                },
        }
    }
}Clone, #[automatically_derived]
impl<N: ::core::fmt::Debug, S: ::core::fmt::Debug, A: ::core::fmt::Debug +
    Annotation> ::core::fmt::Debug for NodeState<N, S, A> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            NodeState::NotVisited =>
                ::core::fmt::Formatter::write_str(f, "NotVisited"),
            NodeState::BeingVisited { depth: __self_0, annotation: __self_1 }
                =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "BeingVisited", "depth", __self_0, "annotation", &__self_1),
            NodeState::InCycle { scc_index: __self_0, annotation: __self_1 }
                =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "InCycle", "scc_index", __self_0, "annotation", &__self_1),
            NodeState::InCycleWith { parent: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "InCycleWith", "parent", &__self_0),
        }
    }
}Debug)]
259enum NodeState<N, S, A: Annotation> {
260    /// This node has not yet been visited as part of the DFS.
261    ///
262    /// After SCC construction is complete, this state ought to be
263    /// impossible.
264    NotVisited,
265
266    /// This node is currently being walked as part of our DFS. It is on
267    /// the stack at the depth `depth` and its current annotation is
268    /// `annotation`.
269    ///
270    /// After SCC construction is complete, this state ought to be
271    /// impossible.
272    BeingVisited { depth: usize, annotation: A },
273
274    /// Indicates that this node is a member of the given cycle where
275    /// the merged annotation is `annotation`.
276    /// Note that an SCC can have several cycles, so its final annotation
277    /// is the merged value of all its member annotations.
278    InCycle { scc_index: S, annotation: A },
279
280    /// Indicates that this node is a member of whatever cycle
281    /// `parent` is a member of. This state is transient: whenever we
282    /// see it, we try to overwrite it with the current state of
283    /// `parent` (this is the "path compression" step of a union-find
284    /// algorithm).
285    InCycleWith { parent: N },
286}
287
288/// The state of walking a given node.
289#[derive(#[automatically_derived]
impl<S: ::core::marker::Copy, A: ::core::marker::Copy + Annotation>
    ::core::marker::Copy for WalkReturn<S, A> {
}Copy, #[automatically_derived]
impl<S: ::core::clone::Clone, A: ::core::clone::Clone + Annotation>
    ::core::clone::Clone for WalkReturn<S, A> {
    #[inline]
    fn clone(&self) -> WalkReturn<S, A> {
        match self {
            WalkReturn::Cycle { min_depth: __self_0, annotation: __self_1 } =>
                WalkReturn::Cycle {
                    min_depth: ::core::clone::Clone::clone(__self_0),
                    annotation: ::core::clone::Clone::clone(__self_1),
                },
            WalkReturn::Complete { scc_index: __self_0, annotation: __self_1 }
                =>
                WalkReturn::Complete {
                    scc_index: ::core::clone::Clone::clone(__self_0),
                    annotation: ::core::clone::Clone::clone(__self_1),
                },
        }
    }
}Clone, #[automatically_derived]
impl<S: ::core::fmt::Debug, A: ::core::fmt::Debug + Annotation>
    ::core::fmt::Debug for WalkReturn<S, A> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            WalkReturn::Cycle { min_depth: __self_0, annotation: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "Cycle",
                    "min_depth", __self_0, "annotation", &__self_1),
            WalkReturn::Complete { scc_index: __self_0, annotation: __self_1 }
                =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Complete", "scc_index", __self_0, "annotation", &__self_1),
        }
    }
}Debug)]
290enum WalkReturn<S, A: Annotation> {
291    /// The walk found a cycle, but the entire component is not known to have
292    /// been fully walked yet. We only know the minimum depth of this
293    /// component in a minimum spanning tree of the graph. This component
294    /// is tentatively represented by the state of the first node of this
295    /// cycle we met, which is at `min_depth`.
296    Cycle { min_depth: usize, annotation: A },
297    /// The SCC and everything reachable from it have been fully walked.
298    /// At this point we know what is inside the SCC as we have visited every
299    /// node reachable from it. The SCC can now be fully represented by its ID.
300    Complete { scc_index: S, annotation: A },
301}
302
303impl<'c, 'a, G, A> SccsConstruction<'c, 'a, G, A>
304where
305    G: DirectedGraph + Successors,
306    A: Annotations<G::Node>,
307{
308    /// Identifies SCCs in the graph `G` and computes the resulting
309    /// DAG. This uses a variant of [Tarjan's
310    /// algorithm][wikipedia]. The high-level summary of the algorithm
311    /// is that we do a depth-first search. Along the way, we keep a
312    /// stack of each node whose successors are being visited. We
313    /// track the depth of each node on this stack (there is no depth
314    /// if the node is not on the stack). When we find that some node
315    /// N with depth D can reach some other node N' with lower depth
316    /// D' (i.e., D' < D), we know that N, N', and all nodes in
317    /// between them on the stack are part of an SCC.
318    ///
319    /// Additionally, we keep track of a current annotation of the SCC.
320    ///
321    /// [wikipedia]: https://bit.ly/2EZIx84
322    fn construct(graph: &'c G, annotations: &'a mut A) -> Sccs<G::Node, A::SccIdx> {
323        let num_nodes = graph.num_nodes();
324
325        let mut this = Self {
326            graph,
327            node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes),
328            node_stack: Vec::with_capacity(num_nodes),
329            successors_stack: Vec::new(),
330            scc_data: SccData { scc_details: IndexVec::new(), all_successors: Vec::new() },
331            duplicate_set: FxHashSet::default(),
332            annotations,
333        };
334
335        let scc_indices = graph
336            .iter_nodes()
337            .map(|node| match this.start_walk_from(node) {
338                WalkReturn::Complete { scc_index, .. } => scc_index,
339                WalkReturn::Cycle { min_depth, .. } => {
340                    {
    ::core::panicking::panic_fmt(format_args!("`start_walk_node({0:?})` returned cycle with depth {1:?}",
            node, min_depth));
}panic!("`start_walk_node({node:?})` returned cycle with depth {min_depth:?}")
341                }
342            })
343            .collect();
344
345        Sccs { scc_indices, scc_data: this.scc_data }
346    }
347
348    fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
349        self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node))
350    }
351
352    /// Inspect a node during the DFS. We first examine its current
353    /// state -- if it is not yet visited (`NotVisited`), return `None` so
354    /// that the caller might push it onto the stack and start walking its
355    /// successors.
356    ///
357    /// If it is already on the DFS stack it will be in the state
358    /// `BeingVisited`. In that case, we have found a cycle and we
359    /// return the depth from the stack.
360    ///
361    /// Otherwise, we are looking at a node that has already been
362    /// completely visited. We therefore return `WalkReturn::Complete`
363    /// with its associated SCC index.
364    fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<A::SccIdx, A::Ann>> {
365        Some(match self.find_state(node) {
366            NodeState::InCycle { scc_index, annotation } => {
367                WalkReturn::Complete { scc_index, annotation }
368            }
369
370            NodeState::BeingVisited { depth: min_depth, annotation } => {
371                WalkReturn::Cycle { min_depth, annotation }
372            }
373
374            NodeState::NotVisited => return None,
375
376            NodeState::InCycleWith { parent } => {
    ::core::panicking::panic_fmt(format_args!("`find_state` returned `InCycleWith({0:?})`, which ought to be impossible",
            parent));
}panic!(
377                "`find_state` returned `InCycleWith({parent:?})`, which ought to be impossible"
378            ),
379        })
380    }
381
382    /// Fetches the state of the node `r`. If `r` is recorded as being
383    /// in a cycle with some other node `r2`, then fetches the state
384    /// of `r2` (and updates `r` to reflect current result). This is
385    /// basically the "find" part of a standard union-find algorithm
386    /// (with path compression).
387    fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, A::SccIdx, A::Ann> {
388        // To avoid recursion we temporarily reuse the `parent` of each
389        // InCycleWith link to encode a downwards link while compressing
390        // the path. After we have found the root or deepest node being
391        // visited, we traverse the reverse links and correct the node
392        // states on the way.
393        //
394        // **Note**: This mutation requires that this is a leaf function
395        // or at least that none of the called functions inspects the
396        // current node states. Luckily, we are a leaf.
397
398        // Remember one previous link. The termination condition when
399        // following links downwards is then simply as soon as we have
400        // found the initial self-loop.
401        let mut previous_node = node;
402
403        // Ultimately propagated to all the transitive parents when following
404        // `InCycleWith` upwards.
405        // This loop performs the downward link encoding mentioned above. Details below!
406        // Note that there are two different states being assigned: the root state, and
407        // a potentially derived version of the root state for non-root nodes in the chain.
408        let (root_state, assigned_state) = {
409            loop {
410                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:410",
                        "rustc_data_structures::graph::scc",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(410u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("find_state(r = {1:?} in state {0:?})",
                                                    self.node_states[node], node) as &dyn Value))])
            });
    } else { ; }
};trace!("find_state(r = {node:?} in state {:?})", self.node_states[node]);
411                match self.node_states[node] {
412                    // This must have been the first and only state since it is unexplored*;
413                    // no update needed! * Unless there is a bug :')
414                    s @ NodeState::NotVisited => return s,
415                    // We are in a completely discovered SCC; every node on our path is in that SCC:
416                    s @ NodeState::InCycle { .. } => break (s, s),
417                    // The Interesting Third Base Case: we are a path back to a root node
418                    // still being explored. Now we need that node to keep its state and
419                    // every other node to be recorded as being in whatever component that
420                    // ends up in.
421                    s @ NodeState::BeingVisited { depth, .. } => {
422                        break (s, NodeState::InCycleWith { parent: self.node_stack[depth] });
423                    }
424                    // We are not at the head of a path; keep compressing it!
425                    NodeState::InCycleWith { parent } => {
426                        // We test this, to be extremely sure that we never
427                        // ever break our termination condition for the
428                        // reverse iteration loop.
429                        if !(node != parent) {
    {
        ::core::panicking::panic_fmt(format_args!("Node can not be in cycle with itself"));
    }
};assert!(node != parent, "Node can not be in cycle with itself");
430
431                        // Store the previous node as an inverted list link
432                        self.node_states[node] = NodeState::InCycleWith { parent: previous_node };
433                        // Update to parent node.
434                        previous_node = node;
435                        node = parent;
436                    }
437                }
438            }
439        };
440
441        // The states form a graph where up to one outgoing link is stored at
442        // each node. Initially in general,
443        //
444        //                                                  E
445        //                                                  ^
446        //                                                  |
447        //                                InCycleWith/BeingVisited/NotVisited
448        //                                                  |
449        //   A-InCycleWith->B-InCycleWith…>C-InCycleWith->D-+
450        //   |
451        //   = node, previous_node
452        //
453        // After the first loop, this will look like
454        //                                                  E
455        //                                                  ^
456        //                                                  |
457        //                                InCycleWith/BeingVisited/NotVisited
458        //                                                  |
459        // +>A<-InCycleWith-B<…InCycleWith-C<-InCycleWith-D-+
460        // | |                             |              |
461        // | InCycleWith                   |              = node
462        // +-+                             =previous_node
463        //
464        // Note in particular that A will be linked to itself in a self-cycle
465        // and no other self-cycles occur due to how InCycleWith is assigned in
466        // the find phase implemented by `walk_unvisited_node`.
467        //
468        // We now want to compress the path, that is assign the state of the
469        // link D-E to all other links.
470        //
471        // We can then walk backwards, starting from `previous_node`, and assign
472        // each node in the list with the updated state. The loop terminates
473        // when we reach the self-cycle.
474
475        // Move backwards until we found the node where we started. We
476        // will know when we hit the state where previous_node == node.
477        loop {
478            // Back at the beginning, we can return. Note that we return the root state.
479            // This is because for components being explored, we would otherwise get a
480            // `node_state[n] = InCycleWith{ parent: n }` and that's wrong.
481            if previous_node == node {
482                return root_state;
483            }
484            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:484",
                        "rustc_data_structures::graph::scc",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(484u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("Compressing {0:?} down to {1:?} with state {2:?}",
                                                    node, previous_node, assigned_state) as &dyn Value))])
            });
    } else { ; }
};trace!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}");
485
486            // Update to previous node in the link.
487            match self.node_states[previous_node] {
488                NodeState::InCycleWith { parent: previous } => {
489                    node = previous_node;
490                    previous_node = previous;
491                }
492                // Only InCycleWith nodes were added to the reverse linked list.
493                other => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Invalid previous link while compressing cycle: {0:?}",
                other)));
}unreachable!("Invalid previous link while compressing cycle: {other:?}"),
494            }
495
496            // Update the node state to the (potentially derived) state.
497            // If the root is still being explored, this is
498            // `InCycleWith{ parent: <root node>}`, otherwise
499            // `assigned_state == root_state`.
500            self.node_states[node] = assigned_state;
501        }
502    }
503
504    /// Walks a node that has never been visited before.
505    ///
506    /// Call this method when `inspect_node` has returned `None`. Having the
507    /// caller decide avoids mutual recursion between the two methods and allows
508    /// us to maintain an allocated stack for nodes on the path between calls.
509    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("walk_unvisited_node",
                                    "rustc_data_structures::graph::scc",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(509u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: WalkReturn<A::SccIdx, A::Ann> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:511",
                                    "rustc_data_structures::graph::scc",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(511u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                    ::tracing_core::field::FieldSet::new(&["message"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&format_args!("Walk unvisited node: {0:?}",
                                                                initial) as &dyn Value))])
                        });
                } else { ; }
            };
            struct VisitingNodeFrame<G: DirectedGraph, Successors, A> {
                node: G::Node,
                successors: Option<Successors>,
                depth: usize,
                min_depth: usize,
                successors_len: usize,
                min_cycle_root: G::Node,
                successor_node: G::Node,
                #[doc =
                " The annotation for the SCC starting in `node`. It may or may"]
                #[doc = " not contain other nodes."]
                current_component_annotation: A,
            }
            let mut successors_stack =
                core::mem::take(&mut self.successors_stack);
            if true {
                match (&successors_stack.len(), &0) {
                    (left_val, right_val) => {
                        if !(*left_val == *right_val) {
                            let kind = ::core::panicking::AssertKind::Eq;
                            ::core::panicking::assert_failed(kind, &*left_val,
                                &*right_val, ::core::option::Option::None);
                        }
                    }
                };
            };
            let mut stack: Vec<VisitingNodeFrame<G, _, _>> =
                <[_]>::into_vec(::alloc::boxed::box_new([VisitingNodeFrame {
                                    node: initial,
                                    depth: 0,
                                    min_depth: 0,
                                    successors: None,
                                    successors_len: 0,
                                    min_cycle_root: initial,
                                    successor_node: initial,
                                    current_component_annotation: self.annotations.new(initial),
                                }]));
            let mut return_value = None;
            'recurse:
                while let Some(frame) = stack.last_mut() {
                let VisitingNodeFrame {
                        node,
                        depth,
                        successors,
                        successors_len,
                        min_depth,
                        min_cycle_root,
                        successor_node,
                        current_component_annotation } = frame;
                let node = *node;
                let depth = *depth;
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:558",
                                        "rustc_data_structures::graph::scc",
                                        ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                        ::tracing_core::__macro_support::Option::Some(558u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                        ::tracing_core::field::FieldSet::new(&["message"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("Visiting {0:?} at depth {1:?}, annotation: {2:?}",
                                                                    node, depth, current_component_annotation) as &dyn Value))])
                            });
                    } else { ; }
                };
                let successors =
                    match successors {
                        Some(successors) => successors,
                        None => {
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:566",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(566u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["depth", "node"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&debug(&depth) as
                                                                        &dyn Value)),
                                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&debug(&node) as
                                                                        &dyn Value))])
                                        });
                                } else { ; }
                            };
                            if true {
                                match self.node_states[node] {
                                    NodeState::NotVisited => {}
                                    ref left_val => {
                                        ::core::panicking::assert_matches_failed(left_val,
                                            "NodeState::NotVisited", ::core::option::Option::None);
                                    }
                                };
                            };
                            self.node_states[node] =
                                NodeState::BeingVisited {
                                    depth,
                                    annotation: *current_component_annotation,
                                };
                            self.node_stack.push(node);
                            *successors_len = successors_stack.len();
                            successors.get_or_insert(self.graph.successors(node))
                        }
                    };
                let successors_len = *successors_len;
                let returned_walk =
                    return_value.take().into_iter().map(|walk|
                            (*successor_node, Some(walk)));
                let successor_walk =
                    successors.map(|successor_node|
                            {
                                {
                                    use ::tracing::__macro_support::Callsite as _;
                                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                        {
                                            static META: ::tracing::Metadata<'static> =
                                                {
                                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:596",
                                                        "rustc_data_structures::graph::scc",
                                                        ::tracing::Level::TRACE,
                                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                        ::tracing_core::__macro_support::Option::Some(596u32),
                                                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                        ::tracing_core::field::FieldSet::new(&["node",
                                                                        "successor_node"],
                                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                        ::tracing::metadata::Kind::EVENT)
                                                };
                                            ::tracing::callsite::DefaultCallsite::new(&META)
                                        };
                                    let enabled =
                                        ::tracing::Level::TRACE <=
                                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                ::tracing::Level::TRACE <=
                                                    ::tracing::level_filters::LevelFilter::current() &&
                                            {
                                                let interest = __CALLSITE.interest();
                                                !interest.is_never() &&
                                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                        interest)
                                            };
                                    if enabled {
                                        (|value_set: ::tracing::field::ValueSet|
                                                    {
                                                        let meta = __CALLSITE.metadata();
                                                        ::tracing::Event::dispatch(meta, &value_set);
                                                        ;
                                                    })({
                                                #[allow(unused_imports)]
                                                use ::tracing::field::{debug, display, Value};
                                                let mut iter = __CALLSITE.metadata().fields().iter();
                                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                    ::tracing::__macro_support::Option::Some(&debug(&node) as
                                                                            &dyn Value)),
                                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                    ::tracing::__macro_support::Option::Some(&debug(&successor_node)
                                                                            as &dyn Value))])
                                            });
                                    } else { ; }
                                };
                                (successor_node, self.inspect_node(successor_node))
                            });
                for (successor_node, walk) in
                    returned_walk.chain(successor_walk) {
                    match walk {
                        Some(WalkReturn::Cycle {
                            min_depth: successor_min_depth,
                            annotation: successor_annotation }) => {
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:607",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(607u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["message"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&format_args!("Cycle found from {0:?}, minimum depth: {1:?}, annotation: {2:?}",
                                                                                node, successor_min_depth, successor_annotation) as
                                                                        &dyn Value))])
                                        });
                                } else { ; }
                            };
                            if !(successor_min_depth <= depth) {
                                ::core::panicking::panic("assertion failed: successor_min_depth <= depth")
                            };
                            if successor_min_depth < *min_depth {
                                {
                                    use ::tracing::__macro_support::Callsite as _;
                                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                        {
                                            static META: ::tracing::Metadata<'static> =
                                                {
                                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:613",
                                                        "rustc_data_structures::graph::scc",
                                                        ::tracing::Level::TRACE,
                                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                        ::tracing_core::__macro_support::Option::Some(613u32),
                                                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                        ::tracing_core::field::FieldSet::new(&["node",
                                                                        "successor_min_depth"],
                                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                        ::tracing::metadata::Kind::EVENT)
                                                };
                                            ::tracing::callsite::DefaultCallsite::new(&META)
                                        };
                                    let enabled =
                                        ::tracing::Level::TRACE <=
                                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                ::tracing::Level::TRACE <=
                                                    ::tracing::level_filters::LevelFilter::current() &&
                                            {
                                                let interest = __CALLSITE.interest();
                                                !interest.is_never() &&
                                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                        interest)
                                            };
                                    if enabled {
                                        (|value_set: ::tracing::field::ValueSet|
                                                    {
                                                        let meta = __CALLSITE.metadata();
                                                        ::tracing::Event::dispatch(meta, &value_set);
                                                        ;
                                                    })({
                                                #[allow(unused_imports)]
                                                use ::tracing::field::{debug, display, Value};
                                                let mut iter = __CALLSITE.metadata().fields().iter();
                                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                    ::tracing::__macro_support::Option::Some(&debug(&node) as
                                                                            &dyn Value)),
                                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                    ::tracing::__macro_support::Option::Some(&debug(&successor_min_depth)
                                                                            as &dyn Value))])
                                            });
                                    } else { ; }
                                };
                                *min_depth = successor_min_depth;
                                *min_cycle_root = successor_node;
                            }
                            current_component_annotation.update_scc(successor_annotation);
                        }
                        Some(WalkReturn::Complete {
                            scc_index: successor_scc_index,
                            annotation: successor_annotation }) => {
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:625",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(625u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["message"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&format_args!("Complete; {0:?} is root of complete-visited SCC idx {1:?} with annotation {2:?}",
                                                                                node, successor_scc_index, successor_annotation) as
                                                                        &dyn Value))])
                                        });
                                } else { ; }
                            };
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:630",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(630u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["node",
                                                                    "successor_scc_index"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&debug(&node) as
                                                                        &dyn Value)),
                                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&debug(&successor_scc_index)
                                                                        as &dyn Value))])
                                        });
                                } else { ; }
                            };
                            successors_stack.push(successor_scc_index);
                            current_component_annotation.update_reachable(successor_annotation);
                        }
                        None => {
                            let depth = depth + 1;
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:637",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(637u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["message"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&format_args!("Recursing down into {0:?} at depth {1:?}",
                                                                                successor_node, depth) as &dyn Value))])
                                        });
                                } else { ; }
                            };
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:638",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(638u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["depth",
                                                                    "successor_node"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&debug(&depth) as
                                                                        &dyn Value)),
                                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&debug(&successor_node)
                                                                        as &dyn Value))])
                                        });
                                } else { ; }
                            };
                            frame.successor_node = successor_node;
                            stack.push(VisitingNodeFrame {
                                    node: successor_node,
                                    depth,
                                    successors: None,
                                    successors_len: 0,
                                    min_depth: depth,
                                    min_cycle_root: successor_node,
                                    successor_node,
                                    current_component_annotation: self.annotations.new(successor_node),
                                });
                            continue 'recurse;
                        }
                    }
                }
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:657",
                                        "rustc_data_structures::graph::scc",
                                        ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                        ::tracing_core::__macro_support::Option::Some(657u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                        ::tracing_core::field::FieldSet::new(&["message"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("Finished walk from {0:?} with annotation: {1:?}",
                                                                    node, current_component_annotation) as &dyn Value))])
                            });
                    } else { ; }
                };
                let r = self.node_stack.pop();
                if true {
                    match (&r, &Some(node)) {
                        (left_val, right_val) => {
                            if !(*left_val == *right_val) {
                                let kind = ::core::panicking::AssertKind::Eq;
                                ::core::panicking::assert_failed(kind, &*left_val,
                                    &*right_val, ::core::option::Option::None);
                            }
                        }
                    };
                };
                let frame = stack.pop().unwrap();
                let current_component_annotation =
                    frame.current_component_annotation;
                if true {
                    match (&frame.node, &node) {
                        (left_val, right_val) => {
                            if !(*left_val == *right_val) {
                                let kind = ::core::panicking::AssertKind::Eq;
                                ::core::panicking::assert_failed(kind, &*left_val,
                                    &*right_val, ::core::option::Option::None);
                            }
                        }
                    };
                };
                if true {
                    if !return_value.is_none() {
                        ::core::panicking::panic("assertion failed: return_value.is_none()")
                    };
                };
                return_value =
                    Some(if frame.min_depth == depth {
                            let deduplicated_successors =
                                {
                                    let duplicate_set = &mut self.duplicate_set;
                                    duplicate_set.clear();
                                    successors_stack.drain(successors_len..).filter(move |&i|
                                            duplicate_set.insert(i))
                                };
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_data_structures/src/graph/scc/mod.rs:687",
                                                    "rustc_data_structures::graph::scc",
                                                    ::tracing::Level::DEBUG,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_data_structures/src/graph/scc/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(687u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_data_structures::graph::scc"),
                                                    ::tracing_core::field::FieldSet::new(&["message"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::DEBUG <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::DEBUG <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&format_args!("Creating SCC rooted in {1:?} with successor {0:?}",
                                                                                frame.successor_node, node) as &dyn Value))])
                                        });
                                } else { ; }
                            };
                            let scc_index =
                                self.scc_data.create_scc(deduplicated_successors);
                            self.annotations.annotate_scc(scc_index,
                                current_component_annotation);
                            self.node_states[node] =
                                NodeState::InCycle {
                                    scc_index,
                                    annotation: current_component_annotation,
                                };
                            WalkReturn::Complete {
                                scc_index,
                                annotation: current_component_annotation,
                            }
                        } else {
                            self.node_states[node] =
                                NodeState::InCycleWith { parent: frame.min_cycle_root };
                            WalkReturn::Cycle {
                                min_depth: frame.min_depth,
                                annotation: current_component_annotation,
                            }
                        });
            }
            self.successors_stack = successors_stack;
            if true {
                match (&self.successors_stack.len(), &0) {
                    (left_val, right_val) => {
                        if !(*left_val == *right_val) {
                            let kind = ::core::panicking::AssertKind::Eq;
                            ::core::panicking::assert_failed(kind, &*left_val,
                                &*right_val, ::core::option::Option::None);
                        }
                    }
                };
            };
            return_value.unwrap()
        }
    }
}#[instrument(skip(self, initial), level = "trace")]
510    fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
511        trace!("Walk unvisited node: {initial:?}");
512        struct VisitingNodeFrame<G: DirectedGraph, Successors, A> {
513            node: G::Node,
514            successors: Option<Successors>,
515            depth: usize,
516            min_depth: usize,
517            successors_len: usize,
518            min_cycle_root: G::Node,
519            successor_node: G::Node,
520            /// The annotation for the SCC starting in `node`. It may or may
521            /// not contain other nodes.
522            current_component_annotation: A,
523        }
524
525        // Move the stack to a local variable. We want to utilize the existing allocation and
526        // mutably borrow it without borrowing self at the same time.
527        let mut successors_stack = core::mem::take(&mut self.successors_stack);
528
529        debug_assert_eq!(successors_stack.len(), 0);
530
531        let mut stack: Vec<VisitingNodeFrame<G, _, _>> = vec![VisitingNodeFrame {
532            node: initial,
533            depth: 0,
534            min_depth: 0,
535            successors: None,
536            successors_len: 0,
537            min_cycle_root: initial,
538            successor_node: initial,
539            current_component_annotation: self.annotations.new(initial),
540        }];
541
542        let mut return_value = None;
543
544        'recurse: while let Some(frame) = stack.last_mut() {
545            let VisitingNodeFrame {
546                node,
547                depth,
548                successors,
549                successors_len,
550                min_depth,
551                min_cycle_root,
552                successor_node,
553                current_component_annotation,
554            } = frame;
555            let node = *node;
556            let depth = *depth;
557
558            trace!(
559                "Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}"
560            );
561
562            let successors = match successors {
563                Some(successors) => successors,
564                None => {
565                    // This None marks that we still have the initialize this node's frame.
566                    trace!(?depth, ?node);
567
568                    debug_assert_matches!(self.node_states[node], NodeState::NotVisited);
569
570                    // Push `node` onto the stack.
571                    self.node_states[node] = NodeState::BeingVisited {
572                        depth,
573                        annotation: *current_component_annotation,
574                    };
575                    self.node_stack.push(node);
576
577                    // Walk each successor of the node, looking to see if any of
578                    // them can reach a node that is presently on the stack. If
579                    // so, that means they can also reach us.
580                    *successors_len = successors_stack.len();
581                    // Set and return a reference, this is currently empty.
582                    successors.get_or_insert(self.graph.successors(node))
583                }
584            };
585
586            // Now that the successors iterator is initialized, this is a constant for this frame.
587            let successors_len = *successors_len;
588
589            // Construct iterators for the nodes and walk results. There are two cases:
590            // * The walk of a successor node returned.
591            // * The remaining successor nodes.
592            let returned_walk =
593                return_value.take().into_iter().map(|walk| (*successor_node, Some(walk)));
594
595            let successor_walk = successors.map(|successor_node| {
596                trace!(?node, ?successor_node);
597                (successor_node, self.inspect_node(successor_node))
598            });
599            for (successor_node, walk) in returned_walk.chain(successor_walk) {
600                match walk {
601                    // The starting node `node` leads to a cycle whose earliest node,
602                    // `successor_node`, is at `min_depth`. There may be more cycles.
603                    Some(WalkReturn::Cycle {
604                        min_depth: successor_min_depth,
605                        annotation: successor_annotation,
606                    }) => {
607                        trace!(
608                            "Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}"
609                        );
610                        // Track the minimum depth we can reach.
611                        assert!(successor_min_depth <= depth);
612                        if successor_min_depth < *min_depth {
613                            trace!(?node, ?successor_min_depth);
614                            *min_depth = successor_min_depth;
615                            *min_cycle_root = successor_node;
616                        }
617                        current_component_annotation.update_scc(successor_annotation);
618                    }
619                    // The starting node `node` is succeeded by a fully identified SCC
620                    // which is now added to the set under `scc_index`.
621                    Some(WalkReturn::Complete {
622                        scc_index: successor_scc_index,
623                        annotation: successor_annotation,
624                    }) => {
625                        trace!(
626                            "Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}"
627                        );
628                        // Push the completed SCC indices onto
629                        // the `successors_stack` for later.
630                        trace!(?node, ?successor_scc_index);
631                        successors_stack.push(successor_scc_index);
632                        current_component_annotation.update_reachable(successor_annotation);
633                    }
634                    // `node` has no more (direct) successors; search recursively.
635                    None => {
636                        let depth = depth + 1;
637                        trace!("Recursing down into {successor_node:?} at depth {depth:?}");
638                        trace!(?depth, ?successor_node);
639                        // Remember which node the return value will come from.
640                        frame.successor_node = successor_node;
641                        // Start a new stack frame, then step into it.
642                        stack.push(VisitingNodeFrame {
643                            node: successor_node,
644                            depth,
645                            successors: None,
646                            successors_len: 0,
647                            min_depth: depth,
648                            min_cycle_root: successor_node,
649                            successor_node,
650                            current_component_annotation: self.annotations.new(successor_node),
651                        });
652                        continue 'recurse;
653                    }
654                }
655            }
656
657            trace!("Finished walk from {node:?} with annotation: {current_component_annotation:?}");
658
659            // Completed walk, remove `node` from the stack.
660            let r = self.node_stack.pop();
661            debug_assert_eq!(r, Some(node));
662
663            // Remove the frame, it's done.
664            let frame = stack.pop().unwrap();
665            let current_component_annotation = frame.current_component_annotation;
666            debug_assert_eq!(frame.node, node);
667
668            // If `min_depth == depth`, then we are the root of the
669            // cycle: we can't reach anyone further down the stack.
670
671            // Pass the 'return value' down the stack.
672            // We return one frame at a time so there can't be another return value.
673            debug_assert!(return_value.is_none());
674            return_value = Some(if frame.min_depth == depth {
675                // We are at the head of the component.
676
677                // Note that successor stack may have duplicates, so we
678                // want to remove those:
679                let deduplicated_successors = {
680                    let duplicate_set = &mut self.duplicate_set;
681                    duplicate_set.clear();
682                    successors_stack
683                        .drain(successors_len..)
684                        .filter(move |&i| duplicate_set.insert(i))
685                };
686
687                debug!("Creating SCC rooted in {node:?} with successor {:?}", frame.successor_node);
688
689                let scc_index = self.scc_data.create_scc(deduplicated_successors);
690
691                self.annotations.annotate_scc(scc_index, current_component_annotation);
692
693                self.node_states[node] =
694                    NodeState::InCycle { scc_index, annotation: current_component_annotation };
695
696                WalkReturn::Complete { scc_index, annotation: current_component_annotation }
697            } else {
698                // We are not the head of the cycle. Return back to our
699                // caller. They will take ownership of the
700                // `self.successors` data that we pushed.
701                self.node_states[node] = NodeState::InCycleWith { parent: frame.min_cycle_root };
702                WalkReturn::Cycle {
703                    min_depth: frame.min_depth,
704                    annotation: current_component_annotation,
705                }
706            });
707        }
708
709        // Keep the allocation we used for successors_stack.
710        self.successors_stack = successors_stack;
711        debug_assert_eq!(self.successors_stack.len(), 0);
712
713        return_value.unwrap()
714    }
715}