@@ -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