11use std:: io;
22
3- use rustc_data_structures:: fx:: FxHashSet ;
3+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
44use rustc_index:: IndexVec ;
55use rustc_middle:: mir:: pretty:: {
66 PassWhere , PrettyPrintMirOptions , create_dump_file, dump_enabled, dump_mir_to_writer,
77} ;
8- use rustc_middle:: mir:: { Body , ClosureRegionRequirements } ;
8+ use rustc_middle:: mir:: { Body , ClosureRegionRequirements , Location } ;
99use rustc_middle:: ty:: { RegionVid , TyCtxt } ;
10+ use rustc_mir_dataflow:: points:: PointIndex ;
1011use rustc_session:: config:: MirIncludeSpans ;
1112
1213use crate :: borrow_set:: BorrowSet ;
1314use crate :: constraints:: OutlivesConstraint ;
1415use crate :: polonius:: { LocalizedOutlivesConstraint , LocalizedOutlivesConstraintSet } ;
16+ use crate :: region_infer:: values:: LivenessValues ;
1517use crate :: type_check:: Locations ;
1618use crate :: { BorrowckInferCtxt , RegionInferenceContext } ;
1719
@@ -80,30 +82,43 @@ fn emit_polonius_dump<'tcx>(
8082 body,
8183 regioncx,
8284 borrow_set,
83- localized_outlives_constraints,
85+ & localized_outlives_constraints,
8486 closure_region_requirements,
8587 out,
8688 ) ?;
8789 writeln ! ( out, "</code></pre>" ) ?;
8890 writeln ! ( out, "</div>" ) ?;
8991
90- // Section 2: mermaid visualization of the CFG.
92+ // Section 2: mermaid visualization of the polonius constraint graph.
93+ writeln ! ( out, "<div>" ) ?;
94+ writeln ! ( out, "Polonius constraint graph" ) ?;
95+ writeln ! ( out, "<pre class='mermaid'>" ) ?;
96+ let edge_count = emit_mermaid_constraint_graph (
97+ borrow_set,
98+ regioncx. liveness_constraints ( ) ,
99+ & localized_outlives_constraints,
100+ out,
101+ ) ?;
102+ writeln ! ( out, "</pre>" ) ?;
103+ writeln ! ( out, "</div>" ) ?;
104+
105+ // Section 3: mermaid visualization of the CFG.
91106 writeln ! ( out, "<div>" ) ?;
92107 writeln ! ( out, "Control-flow graph" ) ?;
93108 writeln ! ( out, "<pre class='mermaid'>" ) ?;
94109 emit_mermaid_cfg ( body, out) ?;
95110 writeln ! ( out, "</pre>" ) ?;
96111 writeln ! ( out, "</div>" ) ?;
97112
98- // Section 3 : mermaid visualization of the NLL region graph.
113+ // Section 4 : mermaid visualization of the NLL region graph.
99114 writeln ! ( out, "<div>" ) ?;
100115 writeln ! ( out, "NLL regions" ) ?;
101116 writeln ! ( out, "<pre class='mermaid'>" ) ?;
102117 emit_mermaid_nll_regions ( regioncx, out) ?;
103118 writeln ! ( out, "</pre>" ) ?;
104119 writeln ! ( out, "</div>" ) ?;
105120
106- // Section 4 : mermaid visualization of the NLL SCC graph.
121+ // Section 5 : mermaid visualization of the NLL SCC graph.
107122 writeln ! ( out, "<div>" ) ?;
108123 writeln ! ( out, "NLL SCCs" ) ?;
109124 writeln ! ( out, "<pre class='mermaid'>" ) ?;
@@ -117,7 +132,11 @@ fn emit_polonius_dump<'tcx>(
117132 "<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
118133 ) ?;
119134 writeln ! ( out, "<script>" ) ?;
120- writeln ! ( out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});" ) ?;
135+ writeln ! (
136+ out,
137+ "mermaid.initialize({{ startOnLoad: false, maxEdges: {} }});" ,
138+ edge_count. max( 100 ) ,
139+ ) ?;
121140 writeln ! ( out, "mermaid.run({{ querySelector: '.mermaid' }})" ) ?;
122141 writeln ! ( out, "</script>" ) ?;
123142 writeln ! ( out, "</body>" ) ?;
@@ -132,7 +151,7 @@ fn emit_html_mir<'tcx>(
132151 body : & Body < ' tcx > ,
133152 regioncx : & RegionInferenceContext < ' tcx > ,
134153 borrow_set : & BorrowSet < ' tcx > ,
135- localized_outlives_constraints : LocalizedOutlivesConstraintSet ,
154+ localized_outlives_constraints : & LocalizedOutlivesConstraintSet ,
136155 closure_region_requirements : & Option < ClosureRegionRequirements < ' tcx > > ,
137156 out : & mut dyn io:: Write ,
138157) -> io:: Result < ( ) > {
@@ -160,7 +179,7 @@ fn emit_html_mir<'tcx>(
160179 regioncx,
161180 closure_region_requirements,
162181 borrow_set,
163- & localized_outlives_constraints,
182+ localized_outlives_constraints,
164183 pass_where,
165184 out,
166185 )
@@ -392,3 +411,76 @@ fn emit_mermaid_nll_sccs<'tcx>(
392411
393412 Ok ( ( ) )
394413}
414+
415+ /// Emits a mermaid flowchart of the polonius localized outlives constraints, with subgraphs per
416+ /// region, and loan introductions.
417+ fn emit_mermaid_constraint_graph < ' tcx > (
418+ borrow_set : & BorrowSet < ' tcx > ,
419+ liveness : & LivenessValues ,
420+ localized_outlives_constraints : & LocalizedOutlivesConstraintSet ,
421+ out : & mut dyn io:: Write ,
422+ ) -> io:: Result < usize > {
423+ let location_name = |location : Location | {
424+ // A MIR location looks like `bb5[2]`. As that is not a syntactically valid mermaid node id,
425+ // transform it into `BB5_2`.
426+ format ! ( "BB{}_{}" , location. block. index( ) , location. statement_index)
427+ } ;
428+ let region_name = |region : RegionVid | format ! ( "'{}" , region. index( ) ) ;
429+ let node_name = |region : RegionVid , point : PointIndex | {
430+ let location = liveness. location_from_point ( point) ;
431+ format ! ( "{}_{}" , region_name( region) , location_name( location) )
432+ } ;
433+
434+ // The mermaid chart type: a top-down flowchart, which supports subgraphs.
435+ writeln ! ( out, "flowchart TD" ) ?;
436+
437+ // The loans subgraph: a node per loan.
438+ writeln ! ( out, " subgraph \" Loans\" " ) ?;
439+ for loan_idx in 0 ..borrow_set. len ( ) {
440+ writeln ! ( out, " L{loan_idx}" ) ?;
441+ }
442+ writeln ! ( out, " end\n " ) ?;
443+
444+ // And an edge from that loan node to where it enters the constraint graph.
445+ for ( loan_idx, loan) in borrow_set. iter_enumerated ( ) {
446+ writeln ! (
447+ out,
448+ " L{} --> {}_{}" ,
449+ loan_idx. index( ) ,
450+ region_name( loan. region) ,
451+ location_name( loan. reserve_location) ,
452+ ) ?;
453+ }
454+ writeln ! ( out, "" ) ?;
455+
456+ // The regions subgraphs containing the region/point nodes.
457+ let mut points_per_region: FxIndexMap < RegionVid , FxIndexSet < PointIndex > > =
458+ FxIndexMap :: default ( ) ;
459+ for constraint in & localized_outlives_constraints. outlives {
460+ points_per_region. entry ( constraint. source ) . or_default ( ) . insert ( constraint. from ) ;
461+ points_per_region. entry ( constraint. target ) . or_default ( ) . insert ( constraint. to ) ;
462+ }
463+ for ( region, points) in points_per_region {
464+ writeln ! ( out, " subgraph \" {}\" " , region_name( region) ) ?;
465+ for point in points {
466+ writeln ! ( out, " {}" , node_name( region, point) ) ?;
467+ }
468+ writeln ! ( out, " end\n " ) ?;
469+ }
470+
471+ // The constraint graph edges.
472+ for constraint in & localized_outlives_constraints. outlives {
473+ // FIXME: add killed loans and constraint kind as edge labels.
474+ writeln ! (
475+ out,
476+ " {} --> {}" ,
477+ node_name( constraint. source, constraint. from) ,
478+ node_name( constraint. target, constraint. to) ,
479+ ) ?;
480+ }
481+
482+ // Return the number of edges: this is the biggest graph in the dump and its edge count will be
483+ // mermaid's max edge count to support.
484+ let edge_count = borrow_set. len ( ) + localized_outlives_constraints. outlives . len ( ) ;
485+ Ok ( edge_count)
486+ }
0 commit comments