|
1 | 1 | use std::io;
|
2 | 2 |
|
3 | 3 | use rustc_data_structures::fx::FxHashSet;
|
| 4 | +use rustc_index::IndexVec; |
4 | 5 | use rustc_middle::mir::pretty::{
|
5 | 6 | PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
|
6 | 7 | };
|
@@ -54,6 +55,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
54 | 55 | /// - the list of polonius localized constraints
|
55 | 56 | /// - a mermaid graph of the CFG
|
56 | 57 | /// - a mermaid graph of the NLL regions and the constraints between them
|
| 58 | +/// - a mermaid graph of the NLL SCCs and the constraints between them |
57 | 59 | fn emit_polonius_dump<'tcx>(
|
58 | 60 | tcx: TyCtxt<'tcx>,
|
59 | 61 | body: &Body<'tcx>,
|
@@ -101,6 +103,14 @@ fn emit_polonius_dump<'tcx>(
|
101 | 103 | writeln!(out, "</pre>")?;
|
102 | 104 | writeln!(out, "</div>")?;
|
103 | 105 |
|
| 106 | + // Section 4: mermaid visualization of the NLL SCC graph. |
| 107 | + writeln!(out, "<div>")?; |
| 108 | + writeln!(out, "NLL SCCs")?; |
| 109 | + writeln!(out, "<pre class='mermaid'>")?; |
| 110 | + emit_mermaid_nll_sccs(regioncx, out)?; |
| 111 | + writeln!(out, "</pre>")?; |
| 112 | + writeln!(out, "</div>")?; |
| 113 | + |
104 | 114 | // Finalize the dump with the HTML epilogue.
|
105 | 115 | writeln!(
|
106 | 116 | out,
|
@@ -343,3 +353,42 @@ fn emit_mermaid_nll_regions<'tcx>(
|
343 | 353 | }
|
344 | 354 | Ok(())
|
345 | 355 | }
|
| 356 | + |
| 357 | +/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar |
| 358 | +/// to the graphviz version. |
| 359 | +fn emit_mermaid_nll_sccs<'tcx>( |
| 360 | + regioncx: &RegionInferenceContext<'tcx>, |
| 361 | + out: &mut dyn io::Write, |
| 362 | +) -> io::Result<()> { |
| 363 | + // The mermaid chart type: a top-down flowchart. |
| 364 | + writeln!(out, "flowchart TD")?; |
| 365 | + |
| 366 | + // Gather and emit the SCC nodes. |
| 367 | + let mut nodes_per_scc: IndexVec<_, _> = |
| 368 | + regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect(); |
| 369 | + for region in regioncx.var_infos.indices() { |
| 370 | + let scc = regioncx.constraint_sccs().scc(region); |
| 371 | + nodes_per_scc[scc].push(region); |
| 372 | + } |
| 373 | + for (scc, regions) in nodes_per_scc.iter_enumerated() { |
| 374 | + // The node label: the regions contained in the SCC. |
| 375 | + write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?; |
| 376 | + for (idx, ®ion) in regions.iter().enumerate() { |
| 377 | + render_region(region, regioncx, out)?; |
| 378 | + if idx < regions.len() - 1 { |
| 379 | + write!(out, ",")?; |
| 380 | + } |
| 381 | + } |
| 382 | + writeln!(out, "}}\"]")?; |
| 383 | + } |
| 384 | + |
| 385 | + // Emit the edges between SCCs. |
| 386 | + let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| { |
| 387 | + regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target)) |
| 388 | + }); |
| 389 | + for (source, target) in edges { |
| 390 | + writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?; |
| 391 | + } |
| 392 | + |
| 393 | + Ok(()) |
| 394 | +} |
0 commit comments