1+ use itertools:: Itertools ;
12use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet , IndexEntry } ;
23use rustc_middle:: mir;
34use rustc_middle:: mir:: coverage:: { BasicCoverageBlock , BranchSpan } ;
@@ -23,38 +24,6 @@ impl ExpnTree {
2324 pub ( crate ) fn get ( & self , expn_id : ExpnId ) -> Option < & ExpnNode > {
2425 self . nodes . get ( & expn_id)
2526 }
26-
27- /// Yields the tree node for the given expansion ID (if present), followed
28- /// by the nodes of all of its descendants in depth-first order.
29- pub ( crate ) fn iter_node_and_descendants (
30- & self ,
31- root_expn_id : ExpnId ,
32- ) -> impl Iterator < Item = & ExpnNode > {
33- gen move {
34- let Some ( root_node) = self . get ( root_expn_id) else { return } ;
35- yield root_node;
36-
37- // Stack of child-node-ID iterators that drives the depth-first traversal.
38- let mut iter_stack = vec ! [ root_node. child_expn_ids. iter( ) ] ;
39-
40- while let Some ( curr_iter) = iter_stack. last_mut ( ) {
41- // Pull the next ID from the top of the stack.
42- let Some ( & curr_id) = curr_iter. next ( ) else {
43- iter_stack. pop ( ) ;
44- continue ;
45- } ;
46-
47- // Yield this node.
48- let Some ( node) = self . get ( curr_id) else { continue } ;
49- yield node;
50-
51- // Push the node's children, to be traversed next.
52- if !node. child_expn_ids . is_empty ( ) {
53- iter_stack. push ( node. child_expn_ids . iter ( ) ) ;
54- }
55- }
56- }
57- }
5827}
5928
6029#[ derive( Debug ) ]
@@ -85,6 +54,10 @@ pub(crate) struct ExpnNode {
8554 pub ( crate ) spans : Vec < SpanWithBcb > ,
8655 /// Expansions whose call-site is in this expansion.
8756 pub ( crate ) child_expn_ids : FxIndexSet < ExpnId > ,
57+ /// The "minimum" and "maximum" BCBs (in dominator order) of ordinary spans
58+ /// belonging to this tree node and all of its descendants. Used when
59+ /// creating a single code mapping representing an entire child expansion.
60+ pub ( crate ) minmax_bcbs : Option < MinMaxBcbs > ,
8861
8962 /// Branch spans (recorded during MIR building) belonging to this expansion.
9063 pub ( crate ) branch_spans : Vec < BranchSpan > ,
@@ -114,6 +87,7 @@ impl ExpnNode {
11487
11588 spans : vec ! [ ] ,
11689 child_expn_ids : FxIndexSet :: default ( ) ,
90+ minmax_bcbs : None ,
11791
11892 branch_spans : vec ! [ ] ,
11993
@@ -164,6 +138,17 @@ pub(crate) fn build_expn_tree(
164138 // Sort the tree nodes into depth-first order.
165139 sort_nodes_depth_first ( & mut nodes) ?;
166140
141+ // For each node, determine its "minimum" and "maximum" BCBs, based on its
142+ // own spans and its immediate children. This relies on the nodes having
143+ // been sorted, so that each node's children are processed before the node
144+ // itself.
145+ for i in ( 0 ..nodes. len ( ) ) . rev ( ) {
146+ // Computing a node's min/max BCBs requires a shared ref to other nodes.
147+ let minmax_bcbs = minmax_bcbs_for_expn_tree_node ( graph, & nodes, & nodes[ i] ) ;
148+ // Now we can mutate the current node to set its min/max BCBs.
149+ nodes[ i] . minmax_bcbs = minmax_bcbs;
150+ }
151+
167152 // If we have a span for the function signature, associate it with the
168153 // corresponding expansion tree node.
169154 if let Some ( fn_sig_span) = hir_info. fn_sig_span
@@ -225,3 +210,31 @@ fn sort_nodes_depth_first(nodes: &mut FxIndexMap<ExpnId, ExpnNode>) -> Result<()
225210
226211 Ok ( ( ) )
227212}
213+
214+ #[ derive( Clone , Copy , Debug ) ]
215+ pub ( crate ) struct MinMaxBcbs {
216+ pub ( crate ) min : BasicCoverageBlock ,
217+ pub ( crate ) max : BasicCoverageBlock ,
218+ }
219+
220+ /// For a single node in the expansion tree, compute its "minimum" and "maximum"
221+ /// BCBs (in dominator order), from among the BCBs of its immediate spans,
222+ /// and the min/max of its immediate children.
223+ fn minmax_bcbs_for_expn_tree_node (
224+ graph : & CoverageGraph ,
225+ nodes : & FxIndexMap < ExpnId , ExpnNode > ,
226+ node : & ExpnNode ,
227+ ) -> Option < MinMaxBcbs > {
228+ let immediate_span_bcbs = node. spans . iter ( ) . map ( |sp : & SpanWithBcb | sp. bcb ) ;
229+ let child_minmax_bcbs = node
230+ . child_expn_ids
231+ . iter ( )
232+ . flat_map ( |id| nodes. get ( id) )
233+ . flat_map ( |child| child. minmax_bcbs )
234+ . flat_map ( |MinMaxBcbs { min, max } | [ min, max] ) ;
235+
236+ let ( min, max) = Iterator :: chain ( immediate_span_bcbs, child_minmax_bcbs)
237+ . minmax_by ( |& a, & b| graph. cmp_in_dominator_order ( a, b) )
238+ . into_option ( ) ?;
239+ Some ( MinMaxBcbs { min, max } )
240+ }
0 commit comments