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. dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()>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. dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()>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 graph_id(&'this self) -> dot::Id<'this>42 fn graph_id(&'this self) -> dot::Id<'this> { 43 dot::Id::new("RegionInferenceContext").unwrap() 44 } node_id(&'this self, n: &RegionVid) -> dot::Id<'this>45 fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> { 46 dot::Id::new(format!("r{}", n.index())).unwrap() 47 } node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>>48 fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> { 49 Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) 50 } node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this>51 fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { 52 dot::LabelText::LabelStr(format!("{:?}", n).into()) 53 } edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this>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 nodes(&'this self) -> dot::Nodes<'this, RegionVid>63 fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { 64 let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect(); 65 vids.into() 66 } edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>>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 source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid74 fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { 75 edge.sup 76 } 77 target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid78 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 graph_id(&'this self) -> dot::Id<'this>92 fn graph_id(&'this self) -> dot::Id<'this> { 93 dot::Id::new("RegionInferenceContext".to_string()).unwrap() 94 } node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this>95 fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { 96 dot::Id::new(format!("r{}", n.index())).unwrap() 97 } node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>>98 fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> { 99 Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) 100 } node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this>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 nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex>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 } edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)>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 source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex135 fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { 136 edge.0 137 } 138 target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex139 fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { 140 edge.1 141 } 142 } 143