|
12 | 12 | //! libgraphviz traits, specialized to attaching borrowck analysis
|
13 | 13 | //! data to rendered labels.
|
14 | 14 |
|
| 15 | +use super::*; |
| 16 | +use borrow_check::nll::constraints::OutlivesConstraint; |
15 | 17 | use dot::{self, IntoCow};
|
16 | 18 | use rustc_data_structures::indexed_vec::Idx;
|
17 | 19 | use std::borrow::Cow;
|
18 | 20 | use std::io::{self, Write};
|
19 |
| -use super::*; |
20 |
| -use borrow_check::nll::constraints::OutlivesConstraint; |
21 | 21 |
|
22 | 22 | impl<'tcx> RegionInferenceContext<'tcx> {
|
23 | 23 | /// Write out the region constraint graph.
|
24 |
| - pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { |
| 24 | + crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { |
25 | 25 | dot::render(&RawConstraints { regioncx: self }, &mut w)
|
26 | 26 | }
|
| 27 | + |
| 28 | + /// Write out the region constraint graph. |
| 29 | + crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { |
| 30 | + let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> = self.constraints_scc |
| 31 | + .all_sccs() |
| 32 | + .map(|_| Vec::new()) |
| 33 | + .collect(); |
| 34 | + |
| 35 | + for region in self.definitions.indices() { |
| 36 | + let scc = self.constraints_scc.scc(region); |
| 37 | + nodes_per_scc[scc].push(region); |
| 38 | + } |
| 39 | + |
| 40 | + dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) |
| 41 | + } |
27 | 42 | }
|
28 | 43 |
|
29 | 44 | struct RawConstraints<'a, 'tcx: 'a> {
|
30 |
| - regioncx: &'a RegionInferenceContext<'tcx> |
| 45 | + regioncx: &'a RegionInferenceContext<'tcx>, |
31 | 46 | }
|
32 | 47 |
|
33 | 48 | impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
|
@@ -63,14 +78,74 @@ impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
|
63 | 78 | (&self.regioncx.constraints.raw[..]).into_cow()
|
64 | 79 | }
|
65 | 80 |
|
66 |
| - // Render `a: b` as `a <- b`, indicating the flow |
| 81 | + // Render `a: b` as `a -> b`, indicating the flow |
67 | 82 | // of data during inference.
|
68 | 83 |
|
69 | 84 | fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
|
70 |
| - edge.sub |
| 85 | + edge.sup |
71 | 86 | }
|
72 | 87 |
|
73 | 88 | fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
|
74 |
| - edge.sup |
| 89 | + edge.sub |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +struct SccConstraints<'a, 'tcx: 'a> { |
| 94 | + regioncx: &'a RegionInferenceContext<'tcx>, |
| 95 | + nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>, |
| 96 | +} |
| 97 | + |
| 98 | +impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { |
| 99 | + type Node = ConstraintSccIndex; |
| 100 | + type Edge = (ConstraintSccIndex, ConstraintSccIndex); |
| 101 | + |
| 102 | + fn graph_id(&'this self) -> dot::Id<'this> { |
| 103 | + dot::Id::new(format!("RegionInferenceContext")).unwrap() |
| 104 | + } |
| 105 | + fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { |
| 106 | + dot::Id::new(format!("r{}", n.index())).unwrap() |
| 107 | + } |
| 108 | + fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> { |
| 109 | + Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) |
| 110 | + } |
| 111 | + fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { |
| 112 | + let nodes = &self.nodes_per_scc[*n]; |
| 113 | + dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into_cow()) |
| 114 | + } |
| 115 | +} |
| 116 | + |
| 117 | +impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { |
| 118 | + type Node = ConstraintSccIndex; |
| 119 | + type Edge = (ConstraintSccIndex, ConstraintSccIndex); |
| 120 | + |
| 121 | + fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { |
| 122 | + let vids: Vec<ConstraintSccIndex> = self.regioncx.constraints_scc.all_sccs().collect(); |
| 123 | + vids.into_cow() |
| 124 | + } |
| 125 | + fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { |
| 126 | + let edges: Vec<_> = self.regioncx |
| 127 | + .constraints_scc |
| 128 | + .all_sccs() |
| 129 | + .flat_map(|scc_a| { |
| 130 | + self.regioncx |
| 131 | + .constraints_scc |
| 132 | + .successors(scc_a) |
| 133 | + .iter() |
| 134 | + .map(move |&scc_b| (scc_a, scc_b)) |
| 135 | + }) |
| 136 | + .collect(); |
| 137 | + |
| 138 | + edges.into_cow() |
| 139 | + } |
| 140 | + |
| 141 | + // Render `a: b` as `a -> b`, indicating the flow |
| 142 | + // of data during inference. |
| 143 | + |
| 144 | + fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { |
| 145 | + edge.0 |
| 146 | + } |
| 147 | + |
| 148 | + fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { |
| 149 | + edge.1 |
75 | 150 | }
|
76 | 151 | }
|
0 commit comments