diff options
Diffstat (limited to 'compiler/rustc_borrowck/src/region_infer/graphviz.rs')
-rw-r--r-- | compiler/rustc_borrowck/src/region_infer/graphviz.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs new file mode 100644 index 000000000..f31ccd74c --- /dev/null +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -0,0 +1,140 @@ +//! This module provides linkage between RegionInferenceContext and +//! `rustc_graphviz` traits, specialized to attaching borrowck analysis +//! data to rendered labels. + +use std::borrow::Cow; +use std::io::{self, Write}; + +use super::*; +use crate::constraints::OutlivesConstraint; +use rustc_graphviz as dot; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Write out the region constraint graph. + pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + dot::render(&RawConstraints { regioncx: self }, &mut w) + } + + /// Write out the region constraint graph. + pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> = + self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); + + for region in self.definitions.indices() { + let scc = self.constraint_sccs.scc(region); + nodes_per_scc[scc].push(region); + } + + dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) + } +} + +struct RawConstraints<'a, 'tcx> { + regioncx: &'a RegionInferenceContext<'tcx>, +} + +impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { + type Node = RegionVid; + type Edge = OutlivesConstraint<'tcx>; + + fn graph_id(&'this self) -> dot::Id<'this> { + dot::Id::new("RegionInferenceContext").unwrap() + } + fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> { + dot::Id::new(format!("r{}", n.index())).unwrap() + } + fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> { + Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) + } + fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { + dot::LabelText::LabelStr(format!("{:?}", n).into()) + } + fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { + dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) + } +} + +impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { + type Node = RegionVid; + type Edge = OutlivesConstraint<'tcx>; + + fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { + let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect(); + vids.into() + } + fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> { + (&self.regioncx.constraints.outlives().raw[..]).into() + } + + // Render `a: b` as `a -> b`, indicating the flow + // of data during inference. + + fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { + edge.sup + } + + fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { + edge.sub + } +} + +struct SccConstraints<'a, 'tcx> { + regioncx: &'a RegionInferenceContext<'tcx>, + nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>, +} + +impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { + type Node = ConstraintSccIndex; + type Edge = (ConstraintSccIndex, ConstraintSccIndex); + + fn graph_id(&'this self) -> dot::Id<'this> { + dot::Id::new("RegionInferenceContext".to_string()).unwrap() + } + fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { + dot::Id::new(format!("r{}", n.index())).unwrap() + } + fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> { + Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) + } + fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { + let nodes = &self.nodes_per_scc[*n]; + dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into()) + } +} + +impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { + type Node = ConstraintSccIndex; + type Edge = (ConstraintSccIndex, ConstraintSccIndex); + + fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { + let vids: Vec<ConstraintSccIndex> = self.regioncx.constraint_sccs.all_sccs().collect(); + vids.into() + } + fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { + let edges: Vec<_> = self + .regioncx + .constraint_sccs + .all_sccs() + .flat_map(|scc_a| { + self.regioncx + .constraint_sccs + .successors(scc_a) + .iter() + .map(move |&scc_b| (scc_a, scc_b)) + }) + .collect(); + + edges.into() + } + + // Render `a: b` as `a -> b`, indicating the flow + // of data during inference. + + fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { + edge.0 + } + + fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { + edge.1 + } +} |