Skip to main content

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::fmt::Debug;
12use std::marker::PhantomData;
13use std::ops::Range;
14
15use rustc_index::{Idx, IndexSlice, IndexVec};
16use tracing::{debug, instrument, trace};
17
18use crate::debug_assert_matches;
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 `update_scc` and `update_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.
38    fn update_scc(&mut self, other: &Self);
39
40    /// Merge a successor into this annotation.
41    fn update_reachable(&mut self, other: &Self);
42}
43
44/// An accumulator for annotations.
45pub trait Annotations<N: Idx> {
46    type Ann: Annotation;
47    type SccIdx: Idx + Ord;
48
49    fn new(&self, element: N) -> Self::Ann;
50    fn annotate_scc(&mut self, scc: Self::SccIdx, annotation: Self::Ann);
51}
52
53/// The nil annotation accumulator, which does nothing.
54struct NoAnnotations<S: Idx + Ord>(PhantomData<S>);
55
56impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
57    type SccIdx = S;
58    type Ann = ();
59    fn new(&self, _element: N) {}
60    fn annotate_scc(&mut self, _scc: S, _annotation: ()) {}
61}
62
63/// The empty annotation, which does nothing.
64impl Annotation for () {
65    fn update_reachable(&mut self, _other: &Self) {}
66    fn update_scc(&mut self, _other: &Self) {}
67}
68
69/// Strongly connected components (SCC) of a graph. The type `N` is
70/// the index type for the graph nodes and `S` is the index type for
71/// the SCCs. We can map from each node to the SCC that it
72/// participates in, and we also have the successors of each SCC.
73pub struct Sccs<N: Idx, S: Idx> {
74    /// For each node, what is the SCC index of the SCC to which it
75    /// belongs.
76    scc_indices: IndexVec<N, S>,
77
78    /// Data about all the SCCs.
79    scc_data: SccData<S>,
80}
81
82/// Information about an invidividual SCC node.
83struct SccDetails {
84    /// For this SCC, the range of `all_successors` where its
85    /// successors can be found.
86    range: Range<usize>,
87}
88
89// The name of this struct should discourage you from making it public and leaking
90// its representation. This message was left here by one who came before you,
91// who learnt the hard way that making even small changes in representation
92// is difficult when it's publicly inspectable.
93//
94// Obey the law of Demeter!
95struct SccData<S: Idx> {
96    /// Maps SCC indices to their metadata, including
97    /// offsets into `all_successors`.
98    scc_details: IndexVec<S, SccDetails>,
99
100    /// Contains the successors for all the Sccs, concatenated. The
101    /// range of indices corresponding to a given SCC is found in its
102    /// `scc_details.range`.
103    all_successors: Vec<S>,
104}
105
106impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
107    /// Compute SCCs without annotations.
108    pub fn new(graph: &impl Successors<Node = N>) -> Self {
109        Self::new_with_annotation(graph, &mut NoAnnotations(PhantomData::<S>))
110    }
111
112    /// Compute SCCs and annotate them with a user-supplied annotation
113    pub fn new_with_annotation<A: Annotations<N, SccIdx = S>>(
114        graph: &impl Successors<Node = N>,
115        annotations: &mut A,
116    ) -> Self {
117        SccsConstruction::construct(graph, annotations)
118    }
119
120    pub fn scc_indices(&self) -> &IndexSlice<N, S> {
121        &self.scc_indices
122    }
123
124    /// Returns the number of SCCs in the graph.
125    pub fn num_sccs(&self) -> usize {
126        self.scc_data.len()
127    }
128
129    /// Returns an iterator over the SCCs in the graph.
130    ///
131    /// The SCCs will be iterated in **dependency order** (or **post order**),
132    /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after.
133    /// This is convenient when the edges represent dependencies: when you visit
134    /// `S1`, the value for `S2` will already have been computed.
135    pub fn all_sccs(&self) -> impl Iterator<Item = S> + 'static {
136        (0..self.scc_data.len()).map(S::new)
137    }
138
139    /// Returns the SCC to which a node `r` belongs.
140    pub fn scc(&self, r: N) -> S {
141        self.scc_indices[r]
142    }
143
144    /// Returns the successors of the given SCC.
145    pub fn successors(&self, scc: S) -> &[S] {
146        self.scc_data.successors(scc)
147    }
148
149    /// Construct the reverse graph of the SCC graph.
150    pub fn reverse(&self) -> VecGraph<S> {
151        VecGraph::new(
152            self.num_sccs(),
153            self.all_sccs()
154                .flat_map(|source| {
155                    self.successors(source).iter().map(move |&target| (target, source))
156                })
157                .collect(),
158        )
159    }
160}
161
162impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> {
163    type Node = S;
164
165    fn num_nodes(&self) -> usize {
166        self.num_sccs()
167    }
168}
169
170impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> {
171    fn num_edges(&self) -> usize {
172        self.scc_data.all_successors.len()
173    }
174}
175
176impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
177    fn successors(&self, node: S) -> impl Iterator<Item = Self::Node> {
178        self.successors(node).iter().cloned()
179    }
180}
181
182impl<S: Idx> SccData<S> {
183    /// Number of SCCs,
184    fn len(&self) -> usize {
185        self.scc_details.len()
186    }
187
188    /// Returns the successors of the given SCC.
189    fn successors(&self, scc: S) -> &[S] {
190        &self.all_successors[self.scc_details[scc].range.clone()]
191    }
192
193    /// Creates a new SCC with `successors` as its successors and
194    /// returns the resulting index.
195    fn create_scc(&mut self, successors: impl IntoIterator<Item = S>) -> S {
196        // Store the successors on `scc_successors_vec`, remembering
197        // the range of indices.
198        let all_successors_start = self.all_successors.len();
199        self.all_successors.extend(successors);
200        let all_successors_end = self.all_successors.len();
201
202        {
    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:202",
                        "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(202u32),
                        ::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!(
203            "create_scc({:?}) successors={:?}",
204            self.len(),
205            &self.all_successors[all_successors_start..all_successors_end],
206        );
207
208        let range = all_successors_start..all_successors_end;
209        let metadata = SccDetails { range };
210        self.scc_details.push(metadata)
211    }
212}
213
214struct SccsConstruction<'c, 'a, G, A>
215where
216    G: DirectedGraph + Successors,
217    A: Annotations<G::Node>,
218{
219    graph: &'c G,
220
221    /// The state of each node; used during walk to record the stack
222    /// and after walk to record what cycle each node ended up being
223    /// in.
224    node_states: IndexVec<G::Node, NodeState<G::Node, A::SccIdx, A::Ann>>,
225
226    /// The stack of nodes that we are visiting as part of the DFS.
227    node_stack: Vec<G::Node>,
228
229    /// The stack of successors: as we visit a node, we mark our
230    /// position in this stack, and when we encounter a successor SCC,
231    /// we push it on the stack. When we complete an SCC, we can pop
232    /// everything off the stack that was found along the way.
233    successors_stack: Vec<A::SccIdx>,
234
235    /// A set used to strip duplicates. As we accumulate successors
236    /// into the successors_stack, we sometimes get duplicate entries.
237    /// We use this set to remove those -- we also keep its storage
238    /// around between successors to amortize memory allocation costs.
239    duplicate_set: FxHashSet<A::SccIdx>,
240
241    scc_data: SccData<A::SccIdx>,
242
243    annotations: &'a mut A,
244}
245
246#[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)]
247enum NodeState<N, S, A: Annotation> {
248    /// This node has not yet been visited as part of the DFS.
249    ///
250    /// After SCC construction is complete, this state ought to be
251    /// impossible.
252    NotVisited,
253
254    /// This node is currently being walked as part of our DFS. It is on
255    /// the stack at the depth `depth` and its current annotation is
256    /// `annotation`.
257    ///
258    /// After SCC construction is complete, this state ought to be
259    /// impossible.
260    BeingVisited { depth: usize, annotation: A },
261
262    /// Indicates that this node is a member of the given cycle where
263    /// the merged annotation is `annotation`.
264    /// Note that an SCC can have several cycles, so its final annotation
265    /// is the merged value of all its member annotations.
266    InCycle { scc_index: S, annotation: A },
267
268    /// Indicates that this node is a member of whatever cycle
269    /// `parent` is a member of. This state is transient: whenever we
270    /// see it, we try to overwrite it with the current state of
271    /// `parent` (this is the "path compression" step of a union-find
272    /// algorithm).
273    InCycleWith { parent: N },
274}
275
276/// The state of walking a given node.
277#[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)]
278enum WalkReturn<S, A: Annotation> {
279    /// The walk found a cycle, but the entire component is not known to have
280    /// been fully walked yet. We only know the minimum depth of this
281    /// component in a minimum spanning tree of the graph. This component
282    /// is tentatively represented by the state of the first node of this
283    /// cycle we met, which is at `min_depth`.
284    Cycle { min_depth: usize, annotation: A },
285    /// The SCC and everything reachable from it have been fully walked.
286    /// At this point we know what is inside the SCC as we have visited every
287    /// node reachable from it. The SCC can now be fully represented by its ID.
288    Complete { scc_index: S, annotation: A },
289}
290
291impl<'c, 'a, G, A> SccsConstruction<'c, 'a, G, A>
292where
293    G: DirectedGraph + Successors,
294    A: Annotations<G::Node>,
295{
296    /// Identifies SCCs in the graph `G` and computes the resulting
297    /// DAG. This uses a variant of [Tarjan's
298    /// algorithm][wikipedia]. The high-level summary of the algorithm
299    /// is that we do a depth-first search. Along the way, we keep a
300    /// stack of each node whose successors are being visited. We
301    /// track the depth of each node on this stack (there is no depth
302    /// if the node is not on the stack). When we find that some node
303    /// N with depth D can reach some other node N' with lower depth
304    /// D' (i.e., D' < D), we know that N, N', and all nodes in
305    /// between them on the stack are part of an SCC.
306    ///
307    /// Additionally, we keep track of a current annotation of the SCC.
308    ///
309    /// [wikipedia]: https://bit.ly/2EZIx84
310    fn construct(graph: &'c G, annotations: &'a mut A) -> Sccs<G::Node, A::SccIdx> {
311        let num_nodes = graph.num_nodes();
312
313        let mut this = Self {
314            graph,
315            node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes),
316            node_stack: Vec::with_capacity(num_nodes),
317            successors_stack: Vec::new(),
318            scc_data: SccData { scc_details: IndexVec::new(), all_successors: Vec::new() },
319            duplicate_set: FxHashSet::default(),
320            annotations,
321        };
322
323        let scc_indices = graph
324            .iter_nodes()
325            .map(|node| match this.start_walk_from(node) {
326                WalkReturn::Complete { scc_index, .. } => scc_index,
327                WalkReturn::Cycle { min_depth, .. } => {
328                    {
    ::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:?}")
329                }
330            })
331            .collect();
332
333        Sccs { scc_indices, scc_data: this.scc_data }
334    }
335
336    fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
337        self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node))
338    }
339
340    /// Inspect a node during the DFS. We first examine its current
341    /// state -- if it is not yet visited (`NotVisited`), return `None` so
342    /// that the caller might push it onto the stack and start walking its
343    /// successors.
344    ///
345    /// If it is already on the DFS stack it will be in the state
346    /// `BeingVisited`. In that case, we have found a cycle and we
347    /// return the depth from the stack.
348    ///
349    /// Otherwise, we are looking at a node that has already been
350    /// completely visited. We therefore return `WalkReturn::Complete`
351    /// with its associated SCC index.
352    fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<A::SccIdx, A::Ann>> {
353        Some(match self.find_state(node) {
354            NodeState::InCycle { scc_index, annotation } => {
355                WalkReturn::Complete { scc_index, annotation }
356            }
357
358            NodeState::BeingVisited { depth: min_depth, annotation } => {
359                WalkReturn::Cycle { min_depth, annotation }
360            }
361
362            NodeState::NotVisited => return None,
363
364            NodeState::InCycleWith { parent } => {
    ::core::panicking::panic_fmt(format_args!("`find_state` returned `InCycleWith({0:?})`, which ought to be impossible",
            parent));
}panic!(
365                "`find_state` returned `InCycleWith({parent:?})`, which ought to be impossible"
366            ),
367        })
368    }
369
370    /// Fetches the state of the node `r`. If `r` is recorded as being
371    /// in a cycle with some other node `r2`, then fetches the state
372    /// of `r2` (and updates `r` to reflect current result). This is
373    /// basically the "find" part of a standard union-find algorithm
374    /// (with path compression).
375    fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, A::SccIdx, A::Ann> {
376        // To avoid recursion we temporarily reuse the `parent` of each
377        // InCycleWith link to encode a downwards link while compressing
378        // the path. After we have found the root or deepest node being
379        // visited, we traverse the reverse links and correct the node
380        // states on the way.
381        //
382        // **Note**: This mutation requires that this is a leaf function
383        // or at least that none of the called functions inspects the
384        // current node states. Luckily, we are a leaf.
385
386        // Remember one previous link. The termination condition when
387        // following links downwards is then simply as soon as we have
388        // found the initial self-loop.
389        let mut previous_node = node;
390
391        // Ultimately propagated to all the transitive parents when following
392        // `InCycleWith` upwards.
393        // This loop performs the downward link encoding mentioned above. Details below!
394        // Note that there are two different states being assigned: the root state, and
395        // a potentially derived version of the root state for non-root nodes in the chain.
396        let (root_state, assigned_state) = {
397            loop {
398                {
    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:398",
                        "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(398u32),
                        ::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]);
399                match self.node_states[node] {
400                    // This must have been the first and only state since it is unexplored*;
401                    // no update needed! * Unless there is a bug :')
402                    s @ NodeState::NotVisited => return s,
403                    // We are in a completely discovered SCC; every node on our path is in that SCC:
404                    s @ NodeState::InCycle { .. } => break (s, s),
405                    // The Interesting Third Base Case: we are a path back to a root node
406                    // still being explored. Now we need that node to keep its state and
407                    // every other node to be recorded as being in whatever component that
408                    // ends up in.
409                    s @ NodeState::BeingVisited { depth, .. } => {
410                        break (s, NodeState::InCycleWith { parent: self.node_stack[depth] });
411                    }
412                    // We are not at the head of a path; keep compressing it!
413                    NodeState::InCycleWith { parent } => {
414                        // We test this, to be extremely sure that we never
415                        // ever break our termination condition for the
416                        // reverse iteration loop.
417                        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");
418
419                        // Store the previous node as an inverted list link
420                        self.node_states[node] = NodeState::InCycleWith { parent: previous_node };
421                        // Update to parent node.
422                        previous_node = node;
423                        node = parent;
424                    }
425                }
426            }
427        };
428
429        // The states form a graph where up to one outgoing link is stored at
430        // each node. Initially in general,
431        //
432        //                                                  E
433        //                                                  ^
434        //                                                  |
435        //                                InCycleWith/BeingVisited/NotVisited
436        //                                                  |
437        //   A-InCycleWith->B-InCycleWith…>C-InCycleWith->D-+
438        //   |
439        //   = node, previous_node
440        //
441        // After the first loop, this will look like
442        //                                                  E
443        //                                                  ^
444        //                                                  |
445        //                                InCycleWith/BeingVisited/NotVisited
446        //                                                  |
447        // +>A<-InCycleWith-B<…InCycleWith-C<-InCycleWith-D-+
448        // | |                             |              |
449        // | InCycleWith                   |              = node
450        // +-+                             =previous_node
451        //
452        // Note in particular that A will be linked to itself in a self-cycle
453        // and no other self-cycles occur due to how InCycleWith is assigned in
454        // the find phase implemented by `walk_unvisited_node`.
455        //
456        // We now want to compress the path, that is assign the state of the
457        // link D-E to all other links.
458        //
459        // We can then walk backwards, starting from `previous_node`, and assign
460        // each node in the list with the updated state. The loop terminates
461        // when we reach the self-cycle.
462
463        // Move backwards until we found the node where we started. We
464        // will know when we hit the state where previous_node == node.
465        loop {
466            // Back at the beginning, we can return. Note that we return the root state.
467            // This is because for components being explored, we would otherwise get a
468            // `node_state[n] = InCycleWith{ parent: n }` and that's wrong.
469            if previous_node == node {
470                return root_state;
471            }
472            {
    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:472",
                        "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(472u32),
                        ::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:?}");
473
474            // Update to previous node in the link.
475            match self.node_states[previous_node] {
476                NodeState::InCycleWith { parent: previous } => {
477                    node = previous_node;
478                    previous_node = previous;
479                }
480                // Only InCycleWith nodes were added to the reverse linked list.
481                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:?}"),
482            }
483
484            // Update the node state to the (potentially derived) state.
485            // If the root is still being explored, this is
486            // `InCycleWith{ parent: <root node>}`, otherwise
487            // `assigned_state == root_state`.
488            self.node_states[node] = assigned_state;
489        }
490    }
491
492    /// Walks a node that has never been visited before.
493    ///
494    /// Call this method when `inspect_node` has returned `None`. Having the
495    /// caller decide avoids mutual recursion between the two methods and allows
496    /// us to maintain an allocated stack for nodes on the path between calls.
497    #[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(497u32),
                                    ::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:499",
                                    "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(499u32),
                                    ::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:546",
                                        "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(546u32),
                                        ::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:554",
                                                    "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(554u32),
                                                    ::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:584",
                                                        "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(584u32),
                                                        ::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:595",
                                                    "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(595u32),
                                                    ::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:601",
                                                        "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(601u32),
                                                        ::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: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(&["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:618",
                                                    "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(618u32),
                                                    ::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: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!("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:626",
                                                    "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(626u32),
                                                    ::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:645",
                                        "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(645u32),
                                        ::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:675",
                                                    "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(675u32),
                                                    ::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")]
498    fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
499        trace!("Walk unvisited node: {initial:?}");
500        struct VisitingNodeFrame<G: DirectedGraph, Successors, A> {
501            node: G::Node,
502            successors: Option<Successors>,
503            depth: usize,
504            min_depth: usize,
505            successors_len: usize,
506            min_cycle_root: G::Node,
507            successor_node: G::Node,
508            /// The annotation for the SCC starting in `node`. It may or may
509            /// not contain other nodes.
510            current_component_annotation: A,
511        }
512
513        // Move the stack to a local variable. We want to utilize the existing allocation and
514        // mutably borrow it without borrowing self at the same time.
515        let mut successors_stack = core::mem::take(&mut self.successors_stack);
516
517        debug_assert_eq!(successors_stack.len(), 0);
518
519        let mut stack: Vec<VisitingNodeFrame<G, _, _>> = vec![VisitingNodeFrame {
520            node: initial,
521            depth: 0,
522            min_depth: 0,
523            successors: None,
524            successors_len: 0,
525            min_cycle_root: initial,
526            successor_node: initial,
527            current_component_annotation: self.annotations.new(initial),
528        }];
529
530        let mut return_value = None;
531
532        'recurse: while let Some(frame) = stack.last_mut() {
533            let VisitingNodeFrame {
534                node,
535                depth,
536                successors,
537                successors_len,
538                min_depth,
539                min_cycle_root,
540                successor_node,
541                current_component_annotation,
542            } = frame;
543            let node = *node;
544            let depth = *depth;
545
546            trace!(
547                "Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}"
548            );
549
550            let successors = match successors {
551                Some(successors) => successors,
552                None => {
553                    // This None marks that we still have the initialize this node's frame.
554                    trace!(?depth, ?node);
555
556                    debug_assert_matches!(self.node_states[node], NodeState::NotVisited);
557
558                    // Push `node` onto the stack.
559                    self.node_states[node] = NodeState::BeingVisited {
560                        depth,
561                        annotation: *current_component_annotation,
562                    };
563                    self.node_stack.push(node);
564
565                    // Walk each successor of the node, looking to see if any of
566                    // them can reach a node that is presently on the stack. If
567                    // so, that means they can also reach us.
568                    *successors_len = successors_stack.len();
569                    // Set and return a reference, this is currently empty.
570                    successors.get_or_insert(self.graph.successors(node))
571                }
572            };
573
574            // Now that the successors iterator is initialized, this is a constant for this frame.
575            let successors_len = *successors_len;
576
577            // Construct iterators for the nodes and walk results. There are two cases:
578            // * The walk of a successor node returned.
579            // * The remaining successor nodes.
580            let returned_walk =
581                return_value.take().into_iter().map(|walk| (*successor_node, Some(walk)));
582
583            let successor_walk = successors.map(|successor_node| {
584                trace!(?node, ?successor_node);
585                (successor_node, self.inspect_node(successor_node))
586            });
587            for (successor_node, walk) in returned_walk.chain(successor_walk) {
588                match walk {
589                    // The starting node `node` leads to a cycle whose earliest node,
590                    // `successor_node`, is at `min_depth`. There may be more cycles.
591                    Some(WalkReturn::Cycle {
592                        min_depth: successor_min_depth,
593                        annotation: successor_annotation,
594                    }) => {
595                        trace!(
596                            "Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}"
597                        );
598                        // Track the minimum depth we can reach.
599                        assert!(successor_min_depth <= depth);
600                        if successor_min_depth < *min_depth {
601                            trace!(?node, ?successor_min_depth);
602                            *min_depth = successor_min_depth;
603                            *min_cycle_root = successor_node;
604                        }
605                        current_component_annotation.update_scc(&successor_annotation);
606                    }
607                    // The starting node `node` is succeeded by a fully identified SCC
608                    // which is now added to the set under `scc_index`.
609                    Some(WalkReturn::Complete {
610                        scc_index: successor_scc_index,
611                        annotation: successor_annotation,
612                    }) => {
613                        trace!(
614                            "Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}"
615                        );
616                        // Push the completed SCC indices onto
617                        // the `successors_stack` for later.
618                        trace!(?node, ?successor_scc_index);
619                        successors_stack.push(successor_scc_index);
620                        current_component_annotation.update_reachable(&successor_annotation);
621                    }
622                    // `node` has no more (direct) successors; search recursively.
623                    None => {
624                        let depth = depth + 1;
625                        trace!("Recursing down into {successor_node:?} at depth {depth:?}");
626                        trace!(?depth, ?successor_node);
627                        // Remember which node the return value will come from.
628                        frame.successor_node = successor_node;
629                        // Start a new stack frame, then step into it.
630                        stack.push(VisitingNodeFrame {
631                            node: successor_node,
632                            depth,
633                            successors: None,
634                            successors_len: 0,
635                            min_depth: depth,
636                            min_cycle_root: successor_node,
637                            successor_node,
638                            current_component_annotation: self.annotations.new(successor_node),
639                        });
640                        continue 'recurse;
641                    }
642                }
643            }
644
645            trace!("Finished walk from {node:?} with annotation: {current_component_annotation:?}");
646
647            // Completed walk, remove `node` from the stack.
648            let r = self.node_stack.pop();
649            debug_assert_eq!(r, Some(node));
650
651            // Remove the frame, it's done.
652            let frame = stack.pop().unwrap();
653            let current_component_annotation = frame.current_component_annotation;
654            debug_assert_eq!(frame.node, node);
655
656            // If `min_depth == depth`, then we are the root of the
657            // cycle: we can't reach anyone further down the stack.
658
659            // Pass the 'return value' down the stack.
660            // We return one frame at a time so there can't be another return value.
661            debug_assert!(return_value.is_none());
662            return_value = Some(if frame.min_depth == depth {
663                // We are at the head of the component.
664
665                // Note that successor stack may have duplicates, so we
666                // want to remove those:
667                let deduplicated_successors = {
668                    let duplicate_set = &mut self.duplicate_set;
669                    duplicate_set.clear();
670                    successors_stack
671                        .drain(successors_len..)
672                        .filter(move |&i| duplicate_set.insert(i))
673                };
674
675                debug!("Creating SCC rooted in {node:?} with successor {:?}", frame.successor_node);
676
677                let scc_index = self.scc_data.create_scc(deduplicated_successors);
678
679                self.annotations.annotate_scc(scc_index, current_component_annotation);
680
681                self.node_states[node] =
682                    NodeState::InCycle { scc_index, annotation: current_component_annotation };
683
684                WalkReturn::Complete { scc_index, annotation: current_component_annotation }
685            } else {
686                // We are not the head of the cycle. Return back to our
687                // caller. They will take ownership of the
688                // `self.successors` data that we pushed.
689                self.node_states[node] = NodeState::InCycleWith { parent: frame.min_cycle_root };
690                WalkReturn::Cycle {
691                    min_depth: frame.min_depth,
692                    annotation: current_component_annotation,
693                }
694            });
695        }
696
697        // Keep the allocation we used for successors_stack.
698        self.successors_stack = successors_stack;
699        debug_assert_eq!(self.successors_stack.len(), 0);
700
701        return_value.unwrap()
702    }
703}