1
Fork 0

Merge {With,Graph}{Successors,Predecessors} into {Successors,Predecessors}

Now with GAT!
This commit is contained in:
Maybe Waffle 2024-04-14 15:40:26 +00:00
parent 398da593a5
commit 0d5fc9bf58
15 changed files with 78 additions and 133 deletions

View file

@ -222,15 +222,10 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph
} }
} }
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> {
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter { type Successors<'g> = Successors<'s, 'tcx, D> where Self: 'g;
fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
self.outgoing_regions(node) self.outgoing_regions(node)
} }
} }
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_>
for RegionGraph<'s, 'tcx, D>
{
type Item = RegionVid;
type Iter = Successors<'s, 'tcx, D>;
}

View file

@ -1,5 +1,5 @@
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::Successors;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{ use rustc_middle::mir::{
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,

View file

@ -2,7 +2,7 @@ use crate::constraints::ConstraintSccIndex;
use crate::RegionInferenceContext; use crate::RegionInferenceContext;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_data_structures::graph::vec_graph::VecGraph;
use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::Successors;
use rustc_middle::ty::RegionVid; use rustc_middle::ty::RegionVid;
use std::ops::Range; use std::ops::Range;

View file

@ -1,5 +1,5 @@
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::Successors;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::interval::IntervalSet; use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::canonical::QueryRegionConstraints;

View file

@ -1,4 +1,4 @@
use super::{DirectedGraph, WithStartNode, WithSuccessors}; use super::{DirectedGraph, Successors, WithStartNode};
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::{IndexSlice, IndexVec}; use rustc_index::{IndexSlice, IndexVec};
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -6,14 +6,14 @@ use std::ops::ControlFlow;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub fn post_order_from<G: DirectedGraph + WithSuccessors>( pub fn post_order_from<G: DirectedGraph + Successors>(
graph: &G, graph: &G,
start_node: G::Node, start_node: G::Node,
) -> Vec<G::Node> { ) -> Vec<G::Node> {
post_order_from_to(graph, start_node, None) post_order_from_to(graph, start_node, None)
} }
pub fn post_order_from_to<G: DirectedGraph + WithSuccessors>( pub fn post_order_from_to<G: DirectedGraph + Successors>(
graph: &G, graph: &G,
start_node: G::Node, start_node: G::Node,
end_node: Option<G::Node>, end_node: Option<G::Node>,
@ -27,7 +27,7 @@ pub fn post_order_from_to<G: DirectedGraph + WithSuccessors>(
result result
} }
fn post_order_walk<G: DirectedGraph + WithSuccessors>( fn post_order_walk<G: DirectedGraph + Successors>(
graph: &G, graph: &G,
node: G::Node, node: G::Node,
result: &mut Vec<G::Node>, result: &mut Vec<G::Node>,
@ -60,7 +60,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors>(
} }
} }
pub fn reverse_post_order<G: DirectedGraph + WithSuccessors>( pub fn reverse_post_order<G: DirectedGraph + Successors>(
graph: &G, graph: &G,
start_node: G::Node, start_node: G::Node,
) -> Vec<G::Node> { ) -> Vec<G::Node> {
@ -72,7 +72,7 @@ pub fn reverse_post_order<G: DirectedGraph + WithSuccessors>(
/// A "depth-first search" iterator for a directed graph. /// A "depth-first search" iterator for a directed graph.
pub struct DepthFirstSearch<'graph, G> pub struct DepthFirstSearch<'graph, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors, G: ?Sized + DirectedGraph + Successors,
{ {
graph: &'graph G, graph: &'graph G,
stack: Vec<G::Node>, stack: Vec<G::Node>,
@ -81,7 +81,7 @@ where
impl<'graph, G> DepthFirstSearch<'graph, G> impl<'graph, G> DepthFirstSearch<'graph, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors, G: ?Sized + DirectedGraph + Successors,
{ {
pub fn new(graph: &'graph G) -> Self { pub fn new(graph: &'graph G) -> Self {
Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
@ -127,7 +127,7 @@ where
impl<G> std::fmt::Debug for DepthFirstSearch<'_, G> impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors, G: ?Sized + DirectedGraph + Successors,
{ {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = fmt.debug_set(); let mut f = fmt.debug_set();
@ -140,7 +140,7 @@ where
impl<G> Iterator for DepthFirstSearch<'_, G> impl<G> Iterator for DepthFirstSearch<'_, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors, G: ?Sized + DirectedGraph + Successors,
{ {
type Item = G::Node; type Item = G::Node;
@ -201,7 +201,7 @@ struct Event<N> {
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
pub struct TriColorDepthFirstSearch<'graph, G> pub struct TriColorDepthFirstSearch<'graph, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors, G: ?Sized + DirectedGraph + Successors,
{ {
graph: &'graph G, graph: &'graph G,
stack: Vec<Event<G::Node>>, stack: Vec<Event<G::Node>>,
@ -211,7 +211,7 @@ where
impl<'graph, G> TriColorDepthFirstSearch<'graph, G> impl<'graph, G> TriColorDepthFirstSearch<'graph, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors, G: ?Sized + DirectedGraph + Successors,
{ {
pub fn new(graph: &'graph G) -> Self { pub fn new(graph: &'graph G) -> Self {
TriColorDepthFirstSearch { TriColorDepthFirstSearch {
@ -278,7 +278,7 @@ where
impl<G> TriColorDepthFirstSearch<'_, G> impl<G> TriColorDepthFirstSearch<'_, G>
where where
G: ?Sized + DirectedGraph + WithSuccessors + WithStartNode, G: ?Sized + DirectedGraph + Successors + WithStartNode,
{ {
/// Performs a depth-first search, starting from `G::start_node()`. /// Performs a depth-first search, starting from `G::start_node()`.
/// ///

View file

@ -20,55 +20,40 @@ pub trait WithNumEdges: DirectedGraph {
fn num_edges(&self) -> usize; fn num_edges(&self) -> usize;
} }
pub trait WithSuccessors: DirectedGraph pub trait Successors: DirectedGraph {
where type Successors<'g>: Iterator<Item = Self::Node>
Self: for<'graph> GraphSuccessors<'graph, Item = <Self as DirectedGraph>::Node>, where
{ Self: 'g;
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter;
fn successors(&self, node: Self::Node) -> Self::Successors<'_>;
fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> { fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> {
iterate::DepthFirstSearch::new(self).with_start_node(from) iterate::DepthFirstSearch::new(self).with_start_node(from)
} }
} }
#[allow(unused_lifetimes)] pub trait Predecessors: DirectedGraph {
pub trait GraphSuccessors<'graph> { type Predecessors<'g>: Iterator<Item = Self::Node>
type Item; where
type Iter: Iterator<Item = Self::Item>; Self: 'g;
}
pub trait WithPredecessors: DirectedGraph fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>;
where
Self: for<'graph> GraphPredecessors<'graph, Item = <Self as DirectedGraph>::Node>,
{
fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter;
}
#[allow(unused_lifetimes)]
pub trait GraphPredecessors<'graph> {
type Item;
type Iter: Iterator<Item = Self::Item>;
} }
pub trait WithStartNode: DirectedGraph { pub trait WithStartNode: DirectedGraph {
fn start_node(&self) -> Self::Node; fn start_node(&self) -> Self::Node;
} }
pub trait ControlFlowGraph: pub trait ControlFlowGraph: DirectedGraph + WithStartNode + Predecessors + Successors {
DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors
{
// convenient trait // convenient trait
} }
impl<T> ControlFlowGraph for T where impl<T> ControlFlowGraph for T where T: DirectedGraph + WithStartNode + Predecessors + Successors {}
T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors
{
}
/// Returns `true` if the graph has a cycle that is reachable from the start node. /// Returns `true` if the graph has a cycle that is reachable from the start node.
pub fn is_cyclic<G>(graph: &G) -> bool pub fn is_cyclic<G>(graph: &G) -> bool
where where
G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors, G: ?Sized + DirectedGraph + WithStartNode + Successors,
{ {
iterate::TriColorDepthFirstSearch::new(graph) iterate::TriColorDepthFirstSearch::new(graph)
.run_from_start(&mut iterate::CycleDetector) .run_from_start(&mut iterate::CycleDetector)

View file

@ -14,24 +14,18 @@ impl<'graph, G: WithStartNode> WithStartNode for &'graph G {
} }
} }
impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { impl<'graph, G: Successors> Successors for &'graph G {
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { type Successors<'g> = G::Successors<'g> where 'graph: 'g;
fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
(**self).successors(node) (**self).successors(node)
} }
} }
impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { impl<'graph, G: Predecessors> Predecessors for &'graph G {
fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter { type Predecessors<'g> = G::Predecessors<'g> where 'graph: 'g;
fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
(**self).predecessors(node) (**self).predecessors(node)
} }
} }
impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G {
type Item = G::Node;
type Iter = <G as GraphPredecessors<'iter>>::Iter;
}
impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G {
type Item = G::Node;
type Iter = <G as GraphSuccessors<'iter>>::Iter;
}

View file

@ -7,7 +7,7 @@
use crate::fx::FxHashSet; use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph; use crate::graph::vec_graph::VecGraph;
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors}; use crate::graph::{DirectedGraph, Successors, WithNumEdges};
use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_index::{Idx, IndexSlice, IndexVec};
use std::ops::Range; use std::ops::Range;
@ -39,7 +39,7 @@ pub struct SccData<S: Idx> {
} }
impl<N: Idx, S: Idx + Ord> Sccs<N, S> { impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
pub fn new(graph: &(impl DirectedGraph<Node = N> + WithSuccessors)) -> Self { pub fn new(graph: &(impl DirectedGraph<Node = N> + Successors)) -> Self {
SccsConstruction::construct(graph) SccsConstruction::construct(graph)
} }
@ -103,14 +103,10 @@ impl<N: Idx, S: Idx + Ord> WithNumEdges for Sccs<N, S> {
} }
} }
impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> { impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
type Item = S; type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, S>>;
type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>; fn successors(&self, node: S) -> Self::Successors<'_> {
}
impl<N: Idx, S: Idx + Ord> WithSuccessors for Sccs<N, S> {
fn successors(&self, node: S) -> <Self as GraphSuccessors<'_>>::Iter {
self.successors(node).iter().cloned() self.successors(node).iter().cloned()
} }
} }
@ -156,7 +152,7 @@ impl<S: Idx> SccData<S> {
} }
} }
struct SccsConstruction<'c, G: DirectedGraph + WithSuccessors, S: Idx> { struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> {
graph: &'c G, graph: &'c G,
/// The state of each node; used during walk to record the stack /// The state of each node; used during walk to record the stack
@ -216,7 +212,7 @@ enum WalkReturn<S> {
impl<'c, G, S> SccsConstruction<'c, G, S> impl<'c, G, S> SccsConstruction<'c, G, S>
where where
G: DirectedGraph + WithSuccessors, G: DirectedGraph + Successors,
S: Idx, S: Idx,
{ {
/// Identifies SCCs in the graph `G` and computes the resulting /// Identifies SCCs in the graph `G` and computes the resulting

View file

@ -48,24 +48,18 @@ impl WithStartNode for TestGraph {
} }
} }
impl WithPredecessors for TestGraph { impl Predecessors for TestGraph {
fn predecessors(&self, node: usize) -> <Self as GraphPredecessors<'_>>::Iter { type Predecessors<'g> = iter::Cloned<slice::Iter<'g, usize>>;
fn predecessors(&self, node: usize) -> Self::Predecessors<'_> {
self.predecessors[&node].iter().cloned() self.predecessors[&node].iter().cloned()
} }
} }
impl WithSuccessors for TestGraph { impl Successors for TestGraph {
fn successors(&self, node: usize) -> <Self as GraphSuccessors<'_>>::Iter { type Successors<'g> = iter::Cloned<slice::Iter<'g, usize>>;
fn successors(&self, node: usize) -> Self::Successors<'_> {
self.successors[&node].iter().cloned() self.successors[&node].iter().cloned()
} }
} }
impl<'graph> GraphPredecessors<'graph> for TestGraph {
type Item = usize;
type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
}
impl<'graph> GraphSuccessors<'graph> for TestGraph {
type Item = usize;
type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
}

View file

@ -1,4 +1,4 @@
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors}; use crate::graph::{DirectedGraph, Successors, WithNumEdges};
use rustc_index::{Idx, IndexVec}; use rustc_index::{Idx, IndexVec};
#[cfg(test)] #[cfg(test)]
@ -92,14 +92,10 @@ impl<N: Idx> WithNumEdges for VecGraph<N> {
} }
} }
impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph<N> { impl<N: Idx + Ord> Successors for VecGraph<N> {
type Item = N; type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, N>>;
type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>; fn successors(&self, node: N) -> Self::Successors<'_> {
}
impl<N: Idx + Ord> WithSuccessors for VecGraph<N> {
fn successors(&self, node: N) -> <Self as GraphSuccessors<'_>>::Iter {
self.successors(node).iter().cloned() self.successors(node).iter().cloned()
} }
} }

View file

@ -1,6 +1,6 @@
use crate::FnCtxt; use crate::FnCtxt;
use rustc_data_structures::{ use rustc_data_structures::{
graph::WithSuccessors, graph::Successors,
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
unord::{UnordBag, UnordMap, UnordSet}, unord::{UnordBag, UnordMap, UnordSet},
}; };

View file

@ -155,26 +155,20 @@ impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
} }
} }
impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> { impl<'tcx> graph::Successors for BasicBlocks<'tcx> {
type Successors<'b> = Successors<'b> where 'tcx: 'b;
#[inline] #[inline]
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter { fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
self.basic_blocks[node].terminator().successors() self.basic_blocks[node].terminator().successors()
} }
} }
impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> { impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> {
type Item = BasicBlock; type Predecessors<'b> = std::iter::Copied<std::slice::Iter<'b, BasicBlock>> where 'tcx: 'b;
type Iter = Successors<'b>;
}
impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
type Item = BasicBlock;
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
}
impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
#[inline] #[inline]
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
self.predecessors()[node].iter().copied() self.predecessors()[node].iter().copied()
} }
} }

View file

@ -5,7 +5,7 @@ use std::io::{self, Write};
pub struct GraphvizWriter< pub struct GraphvizWriter<
'a, 'a,
G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode, G: graph::DirectedGraph + graph::Successors + graph::WithStartNode,
NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
> { > {
@ -19,7 +19,7 @@ pub struct GraphvizWriter<
impl< impl<
'a, 'a,
G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode, G: graph::DirectedGraph + graph::Successors + graph::WithStartNode,
NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>, EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
> GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>

View file

@ -1,7 +1,7 @@
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::{self, Dominators}; use rustc_data_structures::graph::dominators::{self, Dominators};
use rustc_data_structures::graph::{self, DirectedGraph, GraphSuccessors, WithStartNode}; use rustc_data_structures::graph::{self, DirectedGraph, WithStartNode};
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
@ -208,28 +208,20 @@ impl graph::WithStartNode for CoverageGraph {
} }
} }
type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>; impl graph::Successors for CoverageGraph {
type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, BasicCoverageBlock>>;
impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph {
type Item = BasicCoverageBlock;
type Iter = std::iter::Cloned<BcbSuccessors<'graph>>;
}
impl graph::WithSuccessors for CoverageGraph {
#[inline] #[inline]
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
self.successors[node].iter().cloned() self.successors[node].iter().cloned()
} }
} }
impl<'graph> graph::GraphPredecessors<'graph> for CoverageGraph { impl graph::Predecessors for CoverageGraph {
type Item = BasicCoverageBlock; type Predecessors<'g> = std::iter::Copied<std::slice::Iter<'g, BasicCoverageBlock>>;
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicCoverageBlock>>;
}
impl graph::WithPredecessors for CoverageGraph {
#[inline] #[inline]
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
self.predecessors[node].iter().copied() self.predecessors[node].iter().copied()
} }
} }

View file

@ -28,8 +28,7 @@ use super::counters;
use super::graph::{self, BasicCoverageBlock}; use super::graph::{self, BasicCoverageBlock};
use itertools::Itertools; use itertools::Itertools;
use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::{DirectedGraph, Successors};
use rustc_data_structures::graph::DirectedGraph;
use rustc_index::{Idx, IndexVec}; use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty; use rustc_middle::ty;