@@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A>
3232where 
3333    A :  Analysis < ' tcx > , 
3434{ 
35-     body :  & ' mir  Body < ' tcx > , 
36-     results :  RefCell < Option < Results < ' tcx ,  A > > > , 
35+     // The `RefCell` is used because `<Formatter as Labeller>::node_label` 
36+     // takes `&self`, but it needs to modify the cursor. This is also the 
37+     // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has 
38+     // the operations that involve the mutation, i.e. within the `borrow_mut`. 
39+     cursor :  RefCell < ResultsCursor < ' mir ,  ' tcx ,  A > > , 
3740    style :  OutputStyle , 
3841    reachable :  BitSet < BasicBlock > , 
3942} 
@@ -48,11 +51,15 @@ where
4851        style :  OutputStyle , 
4952    )  -> Self  { 
5053        let  reachable = mir:: traversal:: reachable_as_bitset ( body) ; 
51-         Formatter  {  body,  results :  Some ( results) . into ( ) ,  style,  reachable } 
54+         Formatter  {  cursor :  results. into_results_cursor ( body) . into ( ) ,  style,  reachable } 
55+     } 
56+ 
57+     fn  body ( & self )  -> & ' mir  Body < ' tcx >  { 
58+         self . cursor . borrow ( ) . body ( ) 
5259    } 
5360
5461    pub ( crate )  fn  into_results ( self )  -> Results < ' tcx ,  A >  { 
55-         self . results . into_inner ( ) . unwrap ( ) 
62+         self . cursor . into_inner ( ) . into_results ( ) 
5663    } 
5764} 
5865
8188    type  Edge  = CfgEdge ; 
8289
8390    fn  graph_id ( & self )  -> dot:: Id < ' _ >  { 
84-         let  name = graphviz_safe_def_name ( self . body . source . def_id ( ) ) ; 
91+         let  name = graphviz_safe_def_name ( self . body ( ) . source . def_id ( ) ) ; 
8592        dot:: Id :: new ( format ! ( "graph_for_def_id_{name}" ) ) . unwrap ( ) 
8693    } 
8794
@@ -90,20 +97,11 @@ where
9097    } 
9198
9299    fn  node_label ( & self ,  block :  & Self :: Node )  -> dot:: LabelText < ' _ >  { 
93-         let  mut  label = Vec :: new ( ) ; 
94-         self . results . replace_with ( |results| { 
95-             // `Formatter::result` is a `RefCell<Option<_>>` so we can replace 
96-             // the value with `None`, move it into the results cursor, move it 
97-             // back out, and return it to the refcell wrapped in `Some`. 
98-             let  mut  fmt = BlockFormatter  { 
99-                 results :  results. take ( ) . unwrap ( ) . into_results_cursor ( self . body ) , 
100-                 style :  self . style , 
101-                 bg :  Background :: Light , 
102-             } ; 
100+         let  mut  cursor = self . cursor . borrow_mut ( ) ; 
101+         let  mut  fmt =
102+             BlockFormatter  {  cursor :  & mut  cursor,  style :  self . style ,  bg :  Background :: Light  } ; 
103+         let  label = fmt. write_node_label ( * block) . unwrap ( ) ; 
103104
104-             fmt. write_node_label ( & mut  label,  * block) . unwrap ( ) ; 
105-             Some ( fmt. results . into_results ( ) ) 
106-         } ) ; 
107105        dot:: LabelText :: html ( String :: from_utf8 ( label) . unwrap ( ) ) 
108106    } 
109107
@@ -112,20 +110,20 @@ where
112110    } 
113111
114112    fn  edge_label ( & self ,  e :  & Self :: Edge )  -> dot:: LabelText < ' _ >  { 
115-         let  label = & self . body [ e. source ] . terminator ( ) . kind . fmt_successor_labels ( ) [ e. index ] ; 
113+         let  label = & self . body ( ) [ e. source ] . terminator ( ) . kind . fmt_successor_labels ( ) [ e. index ] ; 
116114        dot:: LabelText :: label ( label. clone ( ) ) 
117115    } 
118116} 
119117
120- impl < ' mir ,   ' tcx ,  A >  dot:: GraphWalk < ' mir >  for  Formatter < ' mir ,  ' tcx ,  A > 
118+ impl < ' tcx ,  A >  dot:: GraphWalk < ' _ >  for  Formatter < ' _ ,  ' tcx ,  A > 
121119where 
122120    A :  Analysis < ' tcx > , 
123121{ 
124122    type  Node  = BasicBlock ; 
125123    type  Edge  = CfgEdge ; 
126124
127125    fn  nodes ( & self )  -> dot:: Nodes < ' _ ,  Self :: Node >  { 
128-         self . body 
126+         self . body ( ) 
129127            . basic_blocks 
130128            . indices ( ) 
131129            . filter ( |& idx| self . reachable . contains ( idx) ) 
@@ -134,10 +132,10 @@ where
134132    } 
135133
136134    fn  edges ( & self )  -> dot:: Edges < ' _ ,  Self :: Edge >  { 
137-         self . body 
138-              . basic_blocks 
135+         let  body =  self . body ( ) ; 
136+         body . basic_blocks 
139137            . indices ( ) 
140-             . flat_map ( |bb| dataflow_successors ( self . body ,  bb) ) 
138+             . flat_map ( |bb| dataflow_successors ( body,  bb) ) 
141139            . collect :: < Vec < _ > > ( ) 
142140            . into ( ) 
143141    } 
@@ -147,20 +145,20 @@ where
147145    } 
148146
149147    fn  target ( & self ,  edge :  & Self :: Edge )  -> Self :: Node  { 
150-         self . body [ edge. source ] . terminator ( ) . successors ( ) . nth ( edge. index ) . unwrap ( ) 
148+         self . body ( ) [ edge. source ] . terminator ( ) . successors ( ) . nth ( edge. index ) . unwrap ( ) 
151149    } 
152150} 
153151
154- struct  BlockFormatter < ' mir ,  ' tcx ,  A > 
152+ struct  BlockFormatter < ' a ,   ' mir ,  ' tcx ,  A > 
155153where 
156154    A :  Analysis < ' tcx > , 
157155{ 
158-     results :  ResultsCursor < ' mir ,  ' tcx ,  A > , 
156+     cursor :   & ' a   mut  ResultsCursor < ' mir ,  ' tcx ,  A > , 
159157    bg :  Background , 
160158    style :  OutputStyle , 
161159} 
162160
163- impl < ' mir ,   ' tcx ,  A >  BlockFormatter < ' mir ,  ' tcx ,  A > 
161+ impl < ' tcx ,  A >  BlockFormatter < ' _ ,   ' _ ,  ' tcx ,  A > 
164162where 
165163    A :  Analysis < ' tcx > , 
166164    A :: Domain :  DebugWithContext < A > , 
@@ -173,7 +171,9 @@ where
173171        bg
174172    } 
175173
176-     fn  write_node_label ( & mut  self ,  w :  & mut  impl  io:: Write ,  block :  BasicBlock )  -> io:: Result < ( ) >  { 
174+     fn  write_node_label ( & mut  self ,  block :  BasicBlock )  -> io:: Result < Vec < u8 > >  { 
175+         use  std:: io:: Write ; 
176+ 
177177        //   Sample output: 
178178        //   +-+-----------------------------------------------+ 
179179        // A |                      bb4                        | 
@@ -200,6 +200,9 @@ where
200200        // attributes. Make sure to test the output before trying to remove the redundancy. 
201201        // Notably, `align` was found to have no effect when applied only to <table>. 
202202
203+         let  mut  v = vec ! [ ] ; 
204+         let  w = & mut  v; 
205+ 
203206        let  table_fmt = concat ! ( 
204207            " border=\" 1\" " , 
205208            " cellborder=\" 1\" " , 
@@ -219,21 +222,21 @@ where
219222
220223        // C: State at start of block 
221224        self . bg  = Background :: Light ; 
222-         self . results . seek_to_block_start ( block) ; 
223-         let  block_start_state = self . results . get ( ) . clone ( ) ; 
225+         self . cursor . seek_to_block_start ( block) ; 
226+         let  block_start_state = self . cursor . get ( ) . clone ( ) ; 
224227        self . write_row_with_full_state ( w,  "" ,  "(on start)" ) ?; 
225228
226229        // D + E: Statement and terminator transfer functions 
227230        self . write_statements_and_terminator ( w,  block) ?; 
228231
229232        // F: State at end of block 
230233
231-         let  terminator = self . results . body ( ) [ block] . terminator ( ) ; 
234+         let  terminator = self . cursor . body ( ) [ block] . terminator ( ) ; 
232235
233236        // Write the full dataflow state immediately after the terminator if it differs from the 
234237        // state at block entry. 
235-         self . results . seek_to_block_end ( block) ; 
236-         if  self . results . get ( )  != & block_start_state || A :: Direction :: IS_BACKWARD  { 
238+         self . cursor . seek_to_block_end ( block) ; 
239+         if  self . cursor . get ( )  != & block_start_state || A :: Direction :: IS_BACKWARD  { 
237240            let  after_terminator_name = match  terminator. kind  { 
238241                mir:: TerminatorKind :: Call  {  target :  Some ( _) ,  .. }  => "(on unwind)" , 
239242                _ => "(on end)" , 
@@ -250,8 +253,8 @@ where
250253        match  terminator. kind  { 
251254            mir:: TerminatorKind :: Call  {  destination,  .. }  => { 
252255                self . write_row ( w,  "" ,  "(on successful return)" ,  |this,  w,  fmt| { 
253-                     let  state_on_unwind = this. results . get ( ) . clone ( ) ; 
254-                     this. results . apply_custom_effect ( |analysis,  state| { 
256+                     let  state_on_unwind = this. cursor . get ( ) . clone ( ) ; 
257+                     this. cursor . apply_custom_effect ( |analysis,  state| { 
255258                        analysis. apply_call_return_effect ( 
256259                            state, 
257260                            block, 
@@ -265,18 +268,18 @@ where
265268                        colspan = this. style. num_state_columns( ) , 
266269                        fmt = fmt, 
267270                        diff = diff_pretty( 
268-                             this. results . get( ) , 
271+                             this. cursor . get( ) , 
269272                            & state_on_unwind, 
270-                             this. results . analysis( ) 
273+                             this. cursor . analysis( ) 
271274                        ) , 
272275                    ) 
273276                } ) ?; 
274277            } 
275278
276279            mir:: TerminatorKind :: Yield  {  resume,  resume_arg,  .. }  => { 
277280                self . write_row ( w,  "" ,  "(on yield resume)" ,  |this,  w,  fmt| { 
278-                     let  state_on_coroutine_drop = this. results . get ( ) . clone ( ) ; 
279-                     this. results . apply_custom_effect ( |analysis,  state| { 
281+                     let  state_on_coroutine_drop = this. cursor . get ( ) . clone ( ) ; 
282+                     this. cursor . apply_custom_effect ( |analysis,  state| { 
280283                        analysis. apply_call_return_effect ( 
281284                            state, 
282285                            resume, 
@@ -290,9 +293,9 @@ where
290293                        colspan = this. style. num_state_columns( ) , 
291294                        fmt = fmt, 
292295                        diff = diff_pretty( 
293-                             this. results . get( ) , 
296+                             this. cursor . get( ) , 
294297                            & state_on_coroutine_drop, 
295-                             this. results . analysis( ) 
298+                             this. cursor . analysis( ) 
296299                        ) , 
297300                    ) 
298301                } ) ?; 
@@ -302,8 +305,8 @@ where
302305                if  !targets. is_empty ( )  =>
303306            { 
304307                self . write_row ( w,  "" ,  "(on successful return)" ,  |this,  w,  fmt| { 
305-                     let  state_on_unwind = this. results . get ( ) . clone ( ) ; 
306-                     this. results . apply_custom_effect ( |analysis,  state| { 
308+                     let  state_on_unwind = this. cursor . get ( ) . clone ( ) ; 
309+                     this. cursor . apply_custom_effect ( |analysis,  state| { 
307310                        analysis. apply_call_return_effect ( 
308311                            state, 
309312                            block, 
@@ -317,9 +320,9 @@ where
317320                        colspan = this. style. num_state_columns( ) , 
318321                        fmt = fmt, 
319322                        diff = diff_pretty( 
320-                             this. results . get( ) , 
323+                             this. cursor . get( ) , 
321324                            & state_on_unwind, 
322-                             this. results . analysis( ) 
325+                             this. cursor . analysis( ) 
323326                        ) , 
324327                    ) 
325328                } ) ?; 
@@ -328,7 +331,9 @@ where
328331            _ => { } 
329332        } ; 
330333
331-         write ! ( w,  "</table>" ) 
334+         write ! ( w,  "</table>" ) ?; 
335+ 
336+         Ok ( v) 
332337    } 
333338
334339    fn  write_block_header_simple ( 
@@ -407,9 +412,9 @@ where
407412        block :  BasicBlock , 
408413    )  -> io:: Result < ( ) >  { 
409414        let  diffs = StateDiffCollector :: run ( 
410-             self . results . body ( ) , 
415+             self . cursor . body ( ) , 
411416            block, 
412-             self . results . mut_results ( ) , 
417+             self . cursor . mut_results ( ) , 
413418            self . style , 
414419        ) ; 
415420
@@ -420,7 +425,7 @@ where
420425            if  A :: Direction :: IS_FORWARD  {  it. next ( ) . unwrap ( )  }  else  {  it. next_back ( ) . unwrap ( )  } 
421426        } ; 
422427
423-         for  ( i,  statement)  in  self . results . body ( ) [ block] . statements . iter ( ) . enumerate ( )  { 
428+         for  ( i,  statement)  in  self . cursor . body ( ) [ block] . statements . iter ( ) . enumerate ( )  { 
424429            let  statement_str = format ! ( "{statement:?}" ) ; 
425430            let  index_str = format ! ( "{i}" ) ; 
426431
@@ -442,7 +447,7 @@ where
442447        assert ! ( diffs_after. is_empty( ) ) ; 
443448        assert ! ( diffs_before. as_ref( ) . map_or( true ,  ExactSizeIterator :: is_empty) ) ; 
444449
445-         let  terminator = self . results . body ( ) [ block] . terminator ( ) ; 
450+         let  terminator = self . cursor . body ( ) [ block] . terminator ( ) ; 
446451        let  mut  terminator_str = String :: new ( ) ; 
447452        terminator. kind . fmt_head ( & mut  terminator_str) . unwrap ( ) ; 
448453
@@ -492,8 +497,8 @@ where
492497        mir :  & str , 
493498    )  -> io:: Result < ( ) >  { 
494499        self . write_row ( w,  i,  mir,  |this,  w,  fmt| { 
495-             let  state = this. results . get ( ) ; 
496-             let  analysis = this. results . analysis ( ) ; 
500+             let  state = this. cursor . get ( ) ; 
501+             let  analysis = this. cursor . analysis ( ) ; 
497502
498503            // FIXME: The full state vector can be quite long. It would be nice to split on commas 
499504            // and use some text wrapping algorithm. 
0 commit comments