11use  std:: io; 
22
3+ use  rustc_data_structures:: fx:: FxHashSet ; 
4+ use  rustc_index:: IndexVec ; 
35use  rustc_middle:: mir:: pretty:: { 
46    PassWhere ,  PrettyPrintMirOptions ,  create_dump_file,  dump_enabled,  dump_mir_to_writer, 
57} ; 
68use  rustc_middle:: mir:: { Body ,  ClosureRegionRequirements } ; 
7- use  rustc_middle:: ty:: TyCtxt ; 
9+ use  rustc_middle:: ty:: { RegionVid ,   TyCtxt } ; 
810use  rustc_session:: config:: MirIncludeSpans ; 
911
1012use  crate :: borrow_set:: BorrowSet ; 
13+ use  crate :: constraints:: OutlivesConstraint ; 
1114use  crate :: polonius:: { LocalizedOutlivesConstraint ,  LocalizedOutlivesConstraintSet } ; 
15+ use  crate :: type_check:: Locations ; 
1216use  crate :: { BorrowckInferCtxt ,  RegionInferenceContext } ; 
1317
1418/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information. 
@@ -50,6 +54,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
5054/// - the NLL MIR 
5155/// - the list of polonius localized constraints 
5256/// - a mermaid graph of the CFG 
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 
5359fn  emit_polonius_dump < ' tcx > ( 
5460    tcx :  TyCtxt < ' tcx > , 
5561    body :  & Body < ' tcx > , 
@@ -68,7 +74,7 @@ fn emit_polonius_dump<'tcx>(
6874    // Section 1: the NLL + Polonius MIR. 
6975    writeln ! ( out,  "<div>" ) ?; 
7076    writeln ! ( out,  "Raw MIR dump" ) ?; 
71-     writeln ! ( out,  "<code><pre >" ) ?; 
77+     writeln ! ( out,  "<pre><code >" ) ?; 
7278    emit_html_mir ( 
7379        tcx, 
7480        body, 
@@ -78,15 +84,31 @@ fn emit_polonius_dump<'tcx>(
7884        closure_region_requirements, 
7985        out, 
8086    ) ?; 
81-     writeln ! ( out,  "</pre ></code >" ) ?; 
87+     writeln ! ( out,  "</code ></pre >" ) ?; 
8288    writeln ! ( out,  "</div>" ) ?; 
8389
8490    // Section 2: mermaid visualization of the CFG. 
8591    writeln ! ( out,  "<div>" ) ?; 
8692    writeln ! ( out,  "Control-flow graph" ) ?; 
87-     writeln ! ( out,  "<code>< pre class='mermaid'>" ) ?; 
93+     writeln ! ( out,  "<pre class='mermaid'>" ) ?; 
8894    emit_mermaid_cfg ( body,  out) ?; 
89-     writeln ! ( out,  "</pre></code>" ) ?; 
95+     writeln ! ( out,  "</pre>" ) ?; 
96+     writeln ! ( out,  "</div>" ) ?; 
97+ 
98+     // Section 3: mermaid visualization of the NLL region graph. 
99+     writeln ! ( out,  "<div>" ) ?; 
100+     writeln ! ( out,  "NLL regions" ) ?; 
101+     writeln ! ( out,  "<pre class='mermaid'>" ) ?; 
102+     emit_mermaid_nll_regions ( regioncx,  out) ?; 
103+     writeln ! ( out,  "</pre>" ) ?; 
104+     writeln ! ( out,  "</div>" ) ?; 
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>" ) ?; 
90112    writeln ! ( out,  "</div>" ) ?; 
91113
92114    // Finalize the dump with the HTML epilogue. 
@@ -261,3 +283,112 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()>
261283
262284    Ok ( ( ) ) 
263285} 
286+ 
287+ /// Emits a region's label: index, universe, external name. 
288+ fn  render_region ( 
289+     region :  RegionVid , 
290+     regioncx :  & RegionInferenceContext < ' _ > , 
291+     out :  & mut  dyn  io:: Write , 
292+ )  -> io:: Result < ( ) >  { 
293+     let  def = regioncx. region_definition ( region) ; 
294+     let  universe = def. universe ; 
295+ 
296+     write ! ( out,  "'{}" ,  region. as_usize( ) ) ?; 
297+     if  !universe. is_root ( )  { 
298+         write ! ( out,  "/{universe:?}" ) ?; 
299+     } 
300+     if  let  Some ( name)  = def. external_name . and_then ( |e| e. get_name ( ) )  { 
301+         write ! ( out,  " ({name})" ) ?; 
302+     } 
303+     Ok ( ( ) ) 
304+ } 
305+ 
306+ /// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar 
307+ /// to the graphviz version. 
308+ fn  emit_mermaid_nll_regions < ' tcx > ( 
309+     regioncx :  & RegionInferenceContext < ' tcx > , 
310+     out :  & mut  dyn  io:: Write , 
311+ )  -> io:: Result < ( ) >  { 
312+     // The mermaid chart type: a top-down flowchart. 
313+     writeln ! ( out,  "flowchart TD" ) ?; 
314+ 
315+     // Emit the region nodes. 
316+     for  region in  regioncx. var_infos . indices ( )  { 
317+         write ! ( out,  "{}[\" " ,  region. as_usize( ) ) ?; 
318+         render_region ( region,  regioncx,  out) ?; 
319+         writeln ! ( out,  "\" ]" ) ?; 
320+     } 
321+ 
322+     // Get a set of edges to check for the reverse edge being present. 
323+     let  edges:  FxHashSet < _ >  = regioncx. outlives_constraints ( ) . map ( |c| ( c. sup ,  c. sub ) ) . collect ( ) ; 
324+ 
325+     // Order (and deduplicate) edges for traversal, to display them in a generally increasing order. 
326+     let  constraint_key = |c :  & OutlivesConstraint < ' _ > | { 
327+         let  min = c. sup . min ( c. sub ) ; 
328+         let  max = c. sup . max ( c. sub ) ; 
329+         ( min,  max) 
330+     } ; 
331+     let  mut  ordered_edges:  Vec < _ >  = regioncx. outlives_constraints ( ) . collect ( ) ; 
332+     ordered_edges. sort_by_key ( |c| constraint_key ( c) ) ; 
333+     ordered_edges. dedup_by_key ( |c| constraint_key ( c) ) ; 
334+ 
335+     for  outlives in  ordered_edges { 
336+         // Source node. 
337+         write ! ( out,  "{} " ,  outlives. sup. as_usize( ) ) ?; 
338+ 
339+         // The kind of arrow: bidirectional if the opposite edge exists in the set. 
340+         if  edges. contains ( & ( outlives. sub ,  outlives. sup ) )  { 
341+             write ! ( out,  "<" ) ?; 
342+         } 
343+         write ! ( out,  "-- " ) ?; 
344+ 
345+         // Edge label from its `Locations`. 
346+         match  outlives. locations  { 
347+             Locations :: All ( _)  => write ! ( out,  "All" ) ?, 
348+             Locations :: Single ( location)  => write ! ( out,  "{:?}" ,  location) ?, 
349+         } 
350+ 
351+         // Target node. 
352+         writeln ! ( out,  " --> {}" ,  outlives. sub. as_usize( ) ) ?; 
353+     } 
354+     Ok ( ( ) ) 
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,  & region)  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