#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
use std::borrow::Cow;
use std::io::{self, Write};
use super::*;
use crate::constraints::OutlivesConstraint;
use rustc_graphviz as dot;
impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
dot::render(&RawConstraints { regioncx: self }, &mut w)
}
pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> =
self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect();
for region in self.definitions.indices() {
let scc = self.constraint_sccs.scc(region);
nodes_per_scc[scc].push(region);
}
dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w)
}
}
struct RawConstraints<'a, 'tcx> {
regioncx: &'a RegionInferenceContext<'tcx>,
}
impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
type Node = RegionVid;
type Edge = OutlivesConstraint<'tcx>;
fn graph_id(&'this self) -> dot::Id<'this> {
dot::Id::new("RegionInferenceContext").unwrap()
}
fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> {
dot::Id::new(format!("r{}", n.index())).unwrap()
}
fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> {
Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
}
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{n:?}").into())
}
fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
}
}
impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
type Node = RegionVid;
type Edge = OutlivesConstraint<'tcx>;
fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
vids.into()
}
fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> {
(&self.regioncx.constraints.outlives().raw[..]).into()
}
fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
edge.sup
}
fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
edge.sub
}
}
struct SccConstraints<'a, 'tcx> {
regioncx: &'a RegionInferenceContext<'tcx>,
nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>,
}
impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> {
type Node = ConstraintSccIndex;
type Edge = (ConstraintSccIndex, ConstraintSccIndex);
fn graph_id(&'this self) -> dot::Id<'this> {
dot::Id::new("RegionInferenceContext".to_string()).unwrap()
}
fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> {
dot::Id::new(format!("r{}", n.index())).unwrap()
}
fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option<dot::LabelText<'this>> {
Some(dot::LabelText::LabelStr(Cow::Borrowed("box")))
}
fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> {
let nodes = &self.nodes_per_scc[*n];
dot::LabelText::LabelStr(format!("{n:?} = {nodes:?}").into())
}
}
impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> {
type Node = ConstraintSccIndex;
type Edge = (ConstraintSccIndex, ConstraintSccIndex);
fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> {
let vids: Vec<ConstraintSccIndex> = self.regioncx.constraint_sccs.all_sccs().collect();
vids.into()
}
fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> {
let edges: Vec<_> = self
.regioncx
.constraint_sccs
.all_sccs()
.flat_map(|scc_a| {
self.regioncx
.constraint_sccs
.successors(scc_a)
.iter()
.map(move |&scc_b| (scc_a, scc_b))
})
.collect();
edges.into()
}
fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex {
edge.0
}
fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex {
edge.1
}
}