1 //! This module provides linkage between RegionInferenceContext and
2 //! `rustc_graphviz` traits, specialized to attaching borrowck analysis
3 //! data to rendered labels.
6 use std::io::{self, Write};
9 use crate::constraints::OutlivesConstraint;
10 use rustc_graphviz as dot;
12 impl<'tcx> RegionInferenceContext<'tcx> {
13 /// Write out the region constraint graph.
14 pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
15 dot::render(&RawConstraints { regioncx: self }, &mut w)
18 /// Write out the region constraint graph.
19 pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
20 let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> =
21 self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect();
23 for region in self.definitions.indices() {
24 let scc = self.constraint_sccs.scc(region);
25 nodes_per_scc[scc].push(region);
28 dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w)
32 struct RawConstraints<'a, 'tcx> {
33 regioncx: &'a RegionInferenceContext<'tcx>,
36 impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
37 type Node = RegionVid;
38 type Edge = OutlivesConstraint<'tcx>;
40 fn graph_id(&'this self) -> dot::Id<'this> {
41 dot::Id::new("RegionInferenceContext").unwrap()
43 fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> {
44 dot::Id::new(format!("r{}", n.index())).unwrap()
46 fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> {
47 Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
49 fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
50 dot::LabelText::LabelStr(format!("{:?}", n).into())
52 fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
53 dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
57 impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
58 type Node = RegionVid;
59 type Edge = OutlivesConstraint<'tcx>;
61 fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
62 let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
65 fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> {
66 (&self.regioncx.constraints.outlives().raw[..]).into()
69 // Render `a: b` as `a -> b`, indicating the flow
70 // of data during inference.
72 fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
76 fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
81 struct SccConstraints<'a, 'tcx> {
82 regioncx: &'a RegionInferenceContext<'tcx>,
83 nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>,
86 impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> {
87 type Node = ConstraintSccIndex;
88 type Edge = (ConstraintSccIndex, ConstraintSccIndex);
90 fn graph_id(&'this self) -> dot::Id<'this> {
91 dot::Id::new("RegionInferenceContext".to_string()).unwrap()
93 fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> {
94 dot::Id::new(format!("r{}", n.index())).unwrap()
96 fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> {
97 Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
99 fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> {
100 let nodes = &self.nodes_per_scc[*n];
101 dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into())
105 impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> {
106 type Node = ConstraintSccIndex;
107 type Edge = (ConstraintSccIndex, ConstraintSccIndex);
109 fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> {
110 let vids: Vec<ConstraintSccIndex> = self.regioncx.constraint_sccs.all_sccs().collect();
113 fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> {
114 let edges: Vec<_> = self
123 .map(move |&scc_b| (scc_a, scc_b))
130 // Render `a: b` as `a -> b`, indicating the flow
131 // of data during inference.
133 fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex {
137 fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex {