]>
Commit | Line | Data |
---|---|---|
ff7c6d11 | 1 | //! This module provides linkage between RegionInferenceContext and |
cdc7bbd5 | 2 | //! `rustc_graphviz` traits, specialized to attaching borrowck analysis |
ff7c6d11 XL |
3 | //! data to rendered labels. |
4 | ||
ff7c6d11 XL |
5 | use std::borrow::Cow; |
6 | use std::io::{self, Write}; | |
ff7c6d11 | 7 | |
60c5eb7d | 8 | use super::*; |
c295e0f8 | 9 | use crate::constraints::OutlivesConstraint; |
f035d41b | 10 | use rustc_graphviz as dot; |
60c5eb7d | 11 | |
ff7c6d11 XL |
12 | impl<'tcx> RegionInferenceContext<'tcx> { |
13 | /// Write out the region constraint graph. | |
8faf50e0 XL |
14 | crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { |
15 | dot::render(&RawConstraints { regioncx: self }, &mut w) | |
16 | } | |
17 | ||
18 | /// Write out the region constraint graph. | |
19 | crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { | |
dfeec247 XL |
20 | let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> = |
21 | self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); | |
8faf50e0 XL |
22 | |
23 | for region in self.definitions.indices() { | |
24 | let scc = self.constraint_sccs.scc(region); | |
25 | nodes_per_scc[scc].push(region); | |
26 | } | |
27 | ||
28 | dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) | |
ff7c6d11 XL |
29 | } |
30 | } | |
31 | ||
dc9dc135 | 32 | struct RawConstraints<'a, 'tcx> { |
8faf50e0 XL |
33 | regioncx: &'a RegionInferenceContext<'tcx>, |
34 | } | |
35 | ||
36 | impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { | |
ff7c6d11 | 37 | type Node = RegionVid; |
17df50a5 | 38 | type Edge = OutlivesConstraint<'tcx>; |
ff7c6d11 XL |
39 | |
40 | fn graph_id(&'this self) -> dot::Id<'this> { | |
0bf4aa26 | 41 | dot::Id::new("RegionInferenceContext").unwrap() |
ff7c6d11 XL |
42 | } |
43 | fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> { | |
44 | dot::Id::new(format!("r{}", n.index())).unwrap() | |
45 | } | |
46 | fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> { | |
47 | Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) | |
48 | } | |
49 | fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { | |
0bf4aa26 | 50 | dot::LabelText::LabelStr(format!("{:?}", n).into()) |
ff7c6d11 | 51 | } |
17df50a5 | 52 | fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { |
0bf4aa26 | 53 | dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) |
ff7c6d11 XL |
54 | } |
55 | } | |
56 | ||
8faf50e0 | 57 | impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { |
ff7c6d11 | 58 | type Node = RegionVid; |
17df50a5 | 59 | type Edge = OutlivesConstraint<'tcx>; |
ff7c6d11 XL |
60 | |
61 | fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { | |
8faf50e0 | 62 | let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect(); |
0bf4aa26 | 63 | vids.into() |
ff7c6d11 | 64 | } |
17df50a5 | 65 | fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> { |
dc9dc135 | 66 | (&self.regioncx.constraints.outlives().raw[..]).into() |
ff7c6d11 XL |
67 | } |
68 | ||
8faf50e0 | 69 | // Render `a: b` as `a -> b`, indicating the flow |
ff7c6d11 XL |
70 | // of data during inference. |
71 | ||
17df50a5 | 72 | fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { |
8faf50e0 | 73 | edge.sup |
ff7c6d11 XL |
74 | } |
75 | ||
17df50a5 | 76 | fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { |
8faf50e0 XL |
77 | edge.sub |
78 | } | |
79 | } | |
80 | ||
dc9dc135 | 81 | struct SccConstraints<'a, 'tcx> { |
8faf50e0 XL |
82 | regioncx: &'a RegionInferenceContext<'tcx>, |
83 | nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>, | |
84 | } | |
85 | ||
86 | impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { | |
87 | type Node = ConstraintSccIndex; | |
88 | type Edge = (ConstraintSccIndex, ConstraintSccIndex); | |
89 | ||
90 | fn graph_id(&'this self) -> dot::Id<'this> { | |
91 | dot::Id::new("RegionInferenceContext".to_string()).unwrap() | |
92 | } | |
93 | fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { | |
94 | dot::Id::new(format!("r{}", n.index())).unwrap() | |
95 | } | |
96 | fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> { | |
97 | Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) | |
98 | } | |
99 | fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { | |
100 | let nodes = &self.nodes_per_scc[*n]; | |
0bf4aa26 | 101 | dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into()) |
8faf50e0 XL |
102 | } |
103 | } | |
104 | ||
105 | impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { | |
106 | type Node = ConstraintSccIndex; | |
107 | type Edge = (ConstraintSccIndex, ConstraintSccIndex); | |
108 | ||
109 | fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { | |
110 | let vids: Vec<ConstraintSccIndex> = self.regioncx.constraint_sccs.all_sccs().collect(); | |
0bf4aa26 | 111 | vids.into() |
8faf50e0 XL |
112 | } |
113 | fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { | |
dfeec247 XL |
114 | let edges: Vec<_> = self |
115 | .regioncx | |
8faf50e0 XL |
116 | .constraint_sccs |
117 | .all_sccs() | |
118 | .flat_map(|scc_a| { | |
119 | self.regioncx | |
120 | .constraint_sccs | |
121 | .successors(scc_a) | |
122 | .iter() | |
123 | .map(move |&scc_b| (scc_a, scc_b)) | |
124 | }) | |
125 | .collect(); | |
126 | ||
0bf4aa26 | 127 | edges.into() |
8faf50e0 XL |
128 | } |
129 | ||
130 | // Render `a: b` as `a -> b`, indicating the flow | |
131 | // of data during inference. | |
132 | ||
133 | fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { | |
134 | edge.0 | |
135 | } | |
136 | ||
137 | fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { | |
138 | edge.1 | |
ff7c6d11 XL |
139 | } |
140 | } |