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