]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/borrow_check/region_infer/graphviz.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_mir / borrow_check / region_infer / graphviz.rs
1 //! This module provides linkage between RegionInferenceContext and
2 //! libgraphviz traits, specialized to attaching borrowck analysis
3 //! data to rendered labels.
4
5 use std::borrow::Cow;
6 use std::io::{self, Write};
7
8 use super::*;
9 use crate::borrow_check::constraints::OutlivesConstraint;
10
11 impl<'tcx> RegionInferenceContext<'tcx> {
12 /// Write out the region constraint graph.
13 crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
14 dot::render(&RawConstraints { regioncx: self }, &mut w)
15 }
16
17 /// Write out the region constraint graph.
18 crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
19 let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> = self.constraint_sccs
20 .all_sccs()
21 .map(|_| Vec::new())
22 .collect();
23
24 for region in self.definitions.indices() {
25 let scc = self.constraint_sccs.scc(region);
26 nodes_per_scc[scc].push(region);
27 }
28
29 dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w)
30 }
31 }
32
33 struct RawConstraints<'a, 'tcx> {
34 regioncx: &'a RegionInferenceContext<'tcx>,
35 }
36
37 impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
38 type Node = RegionVid;
39 type Edge = OutlivesConstraint;
40
41 fn graph_id(&'this self) -> dot::Id<'this> {
42 dot::Id::new("RegionInferenceContext").unwrap()
43 }
44 fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> {
45 dot::Id::new(format!("r{}", n.index())).unwrap()
46 }
47 fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> {
48 Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
49 }
50 fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
51 dot::LabelText::LabelStr(format!("{:?}", n).into())
52 }
53 fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
54 dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
55 }
56 }
57
58 impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
59 type Node = RegionVid;
60 type Edge = OutlivesConstraint;
61
62 fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
63 let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
64 vids.into()
65 }
66 fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
67 (&self.regioncx.constraints.outlives().raw[..]).into()
68 }
69
70 // Render `a: b` as `a -> b`, indicating the flow
71 // of data during inference.
72
73 fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
74 edge.sup
75 }
76
77 fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
78 edge.sub
79 }
80 }
81
82 struct SccConstraints<'a, 'tcx> {
83 regioncx: &'a RegionInferenceContext<'tcx>,
84 nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>,
85 }
86
87 impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> {
88 type Node = ConstraintSccIndex;
89 type Edge = (ConstraintSccIndex, ConstraintSccIndex);
90
91 fn graph_id(&'this self) -> dot::Id<'this> {
92 dot::Id::new("RegionInferenceContext".to_string()).unwrap()
93 }
94 fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> {
95 dot::Id::new(format!("r{}", n.index())).unwrap()
96 }
97 fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> {
98 Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
99 }
100 fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> {
101 let nodes = &self.nodes_per_scc[*n];
102 dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into())
103 }
104 }
105
106 impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> {
107 type Node = ConstraintSccIndex;
108 type Edge = (ConstraintSccIndex, ConstraintSccIndex);
109
110 fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> {
111 let vids: Vec<ConstraintSccIndex> = self.regioncx.constraint_sccs.all_sccs().collect();
112 vids.into()
113 }
114 fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> {
115 let edges: Vec<_> = self.regioncx
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
127 edges.into()
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
139 }
140 }