1
1
use std:: io;
2
2
3
- use rustc_data_structures:: fx:: FxHashSet ;
3
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
4
4
use rustc_index:: IndexVec ;
5
5
use rustc_middle:: mir:: pretty:: {
6
6
PassWhere , PrettyPrintMirOptions , create_dump_file, dump_enabled, dump_mir_to_writer,
7
7
} ;
8
- use rustc_middle:: mir:: { Body , ClosureRegionRequirements } ;
8
+ use rustc_middle:: mir:: { Body , ClosureRegionRequirements , Location } ;
9
9
use rustc_middle:: ty:: { RegionVid , TyCtxt } ;
10
+ use rustc_mir_dataflow:: points:: PointIndex ;
10
11
use rustc_session:: config:: MirIncludeSpans ;
11
12
12
13
use crate :: borrow_set:: BorrowSet ;
13
14
use crate :: constraints:: OutlivesConstraint ;
14
15
use crate :: polonius:: { LocalizedOutlivesConstraint , LocalizedOutlivesConstraintSet } ;
16
+ use crate :: region_infer:: values:: LivenessValues ;
15
17
use crate :: type_check:: Locations ;
16
18
use crate :: { BorrowckInferCtxt , RegionInferenceContext } ;
17
19
@@ -80,30 +82,43 @@ fn emit_polonius_dump<'tcx>(
80
82
body,
81
83
regioncx,
82
84
borrow_set,
83
- localized_outlives_constraints,
85
+ & localized_outlives_constraints,
84
86
closure_region_requirements,
85
87
out,
86
88
) ?;
87
89
writeln ! ( out, "</code></pre>" ) ?;
88
90
writeln ! ( out, "</div>" ) ?;
89
91
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.
91
106
writeln ! ( out, "<div>" ) ?;
92
107
writeln ! ( out, "Control-flow graph" ) ?;
93
108
writeln ! ( out, "<pre class='mermaid'>" ) ?;
94
109
emit_mermaid_cfg ( body, out) ?;
95
110
writeln ! ( out, "</pre>" ) ?;
96
111
writeln ! ( out, "</div>" ) ?;
97
112
98
- // Section 3 : mermaid visualization of the NLL region graph.
113
+ // Section 4 : mermaid visualization of the NLL region graph.
99
114
writeln ! ( out, "<div>" ) ?;
100
115
writeln ! ( out, "NLL regions" ) ?;
101
116
writeln ! ( out, "<pre class='mermaid'>" ) ?;
102
117
emit_mermaid_nll_regions ( regioncx, out) ?;
103
118
writeln ! ( out, "</pre>" ) ?;
104
119
writeln ! ( out, "</div>" ) ?;
105
120
106
- // Section 4 : mermaid visualization of the NLL SCC graph.
121
+ // Section 5 : mermaid visualization of the NLL SCC graph.
107
122
writeln ! ( out, "<div>" ) ?;
108
123
writeln ! ( out, "NLL SCCs" ) ?;
109
124
writeln ! ( out, "<pre class='mermaid'>" ) ?;
@@ -117,7 +132,11 @@ fn emit_polonius_dump<'tcx>(
117
132
"<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
118
133
) ?;
119
134
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
+ ) ?;
121
140
writeln ! ( out, "mermaid.run({{ querySelector: '.mermaid' }})" ) ?;
122
141
writeln ! ( out, "</script>" ) ?;
123
142
writeln ! ( out, "</body>" ) ?;
@@ -132,7 +151,7 @@ fn emit_html_mir<'tcx>(
132
151
body : & Body < ' tcx > ,
133
152
regioncx : & RegionInferenceContext < ' tcx > ,
134
153
borrow_set : & BorrowSet < ' tcx > ,
135
- localized_outlives_constraints : LocalizedOutlivesConstraintSet ,
154
+ localized_outlives_constraints : & LocalizedOutlivesConstraintSet ,
136
155
closure_region_requirements : & Option < ClosureRegionRequirements < ' tcx > > ,
137
156
out : & mut dyn io:: Write ,
138
157
) -> io:: Result < ( ) > {
@@ -160,7 +179,7 @@ fn emit_html_mir<'tcx>(
160
179
regioncx,
161
180
closure_region_requirements,
162
181
borrow_set,
163
- & localized_outlives_constraints,
182
+ localized_outlives_constraints,
164
183
pass_where,
165
184
out,
166
185
)
@@ -392,3 +411,76 @@ fn emit_mermaid_nll_sccs<'tcx>(
392
411
393
412
Ok ( ( ) )
394
413
}
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