@@ -61,7 +61,7 @@ pub(super) fn generate_coverage_spans(
6161 hir_info,
6262 basic_coverage_blocks,
6363 ) ;
64- let coverage_spans = SpansRefiner :: refine_sorted_spans ( basic_coverage_blocks , sorted_spans) ;
64+ let coverage_spans = SpansRefiner :: refine_sorted_spans ( sorted_spans) ;
6565 mappings. extend ( coverage_spans. into_iter ( ) . map ( |RefinedCovspan { bcb, span, .. } | {
6666 // Each span produced by the generator represents an ordinary code region.
6767 BcbMapping { kind : BcbMappingKind :: Code ( bcb) , span }
@@ -88,8 +88,6 @@ pub(super) fn generate_coverage_spans(
8888
8989#[ derive( Debug ) ]
9090struct CurrCovspan {
91- /// This is used as the basis for [`PrevCovspan::original_span`], so it must
92- /// not be modified.
9391 span : Span ,
9492 bcb : BasicCoverageBlock ,
9593 is_closure : bool ,
@@ -102,7 +100,7 @@ impl CurrCovspan {
102100
103101 fn into_prev ( self ) -> PrevCovspan {
104102 let Self { span, bcb, is_closure } = self ;
105- PrevCovspan { original_span : span , span, bcb, merged_spans : vec ! [ span] , is_closure }
103+ PrevCovspan { span, bcb, merged_spans : vec ! [ span] , is_closure }
106104 }
107105
108106 fn into_refined ( self ) -> RefinedCovspan {
@@ -115,7 +113,6 @@ impl CurrCovspan {
115113
116114#[ derive( Debug ) ]
117115struct PrevCovspan {
118- original_span : Span ,
119116 span : Span ,
120117 bcb : BasicCoverageBlock ,
121118 /// List of all the original spans from MIR that have been merged into this
@@ -135,42 +132,17 @@ impl PrevCovspan {
135132 self . merged_spans . push ( other. span ) ;
136133 }
137134
138- fn cutoff_statements_at ( & mut self , cutoff_pos : BytePos ) {
135+ fn cutoff_statements_at ( mut self , cutoff_pos : BytePos ) -> Option < RefinedCovspan > {
139136 self . merged_spans . retain ( |span| span. hi ( ) <= cutoff_pos) ;
140137 if let Some ( max_hi) = self . merged_spans . iter ( ) . map ( |span| span. hi ( ) ) . max ( ) {
141138 self . span = self . span . with_hi ( max_hi) ;
142139 }
143- }
144-
145- fn into_dup ( self ) -> DuplicateCovspan {
146- let Self { original_span, span, bcb, merged_spans : _, is_closure } = self ;
147- // Only unmodified spans end up in `pending_dups`.
148- debug_assert_eq ! ( original_span, span) ;
149- DuplicateCovspan { span, bcb, is_closure }
150- }
151-
152- fn refined_copy ( & self ) -> RefinedCovspan {
153- let & Self { original_span : _, span, bcb, merged_spans : _, is_closure } = self ;
154- RefinedCovspan { span, bcb, is_closure }
155- }
156140
157- fn into_refined ( self ) -> RefinedCovspan {
158- self . refined_copy ( )
141+ if self . merged_spans . is_empty ( ) { None } else { Some ( self . into_refined ( ) ) }
159142 }
160- }
161-
162- #[ derive( Debug ) ]
163- struct DuplicateCovspan {
164- span : Span ,
165- bcb : BasicCoverageBlock ,
166- is_closure : bool ,
167- }
168143
169- impl DuplicateCovspan {
170- /// Returns a copy of this covspan, as a [`RefinedCovspan`].
171- /// Should only be called in places that would otherwise clone this covspan.
172144 fn refined_copy ( & self ) -> RefinedCovspan {
173- let & Self { span, bcb, is_closure } = self ;
145+ let & Self { span, bcb, merged_spans : _ , is_closure } = self ;
174146 RefinedCovspan { span, bcb, is_closure }
175147 }
176148
@@ -205,10 +177,7 @@ impl RefinedCovspan {
205177/// * Merge spans that represent continuous (both in source code and control flow), non-branching
206178/// execution
207179/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
208- struct SpansRefiner < ' a > {
209- /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
210- basic_coverage_blocks : & ' a CoverageGraph ,
211-
180+ struct SpansRefiner {
212181 /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
213182 /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
214183 sorted_spans_iter : std:: vec:: IntoIter < SpanFromMir > ,
@@ -223,36 +192,22 @@ struct SpansRefiner<'a> {
223192 /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
224193 some_prev : Option < PrevCovspan > ,
225194
226- /// One or more coverage spans with the same `Span` but different `BasicCoverageBlock`s, and
227- /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
228- /// If a new `curr` span also fits this criteria (compared to an existing list of
229- /// `pending_dups`), that `curr` moves to `prev` before possibly being added to
230- /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups`
231- /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev`
232- /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a
233- /// `prev` with a matching `Span`)
234- pending_dups : Vec < DuplicateCovspan > ,
235-
236195 /// The final coverage spans to add to the coverage map. A `Counter` or `Expression`
237196 /// will also be injected into the MIR for each BCB that has associated spans.
238197 refined_spans : Vec < RefinedCovspan > ,
239198}
240199
241- impl < ' a > SpansRefiner < ' a > {
200+ impl SpansRefiner {
242201 /// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
243202 /// them by merging compatible adjacent spans, removing redundant spans,
244203 /// and carving holes in spans when they overlap in unwanted ways.
245- fn refine_sorted_spans (
246- basic_coverage_blocks : & ' a CoverageGraph ,
247- sorted_spans : Vec < SpanFromMir > ,
248- ) -> Vec < RefinedCovspan > {
204+ fn refine_sorted_spans ( sorted_spans : Vec < SpanFromMir > ) -> Vec < RefinedCovspan > {
205+ let sorted_spans_len = sorted_spans. len ( ) ;
249206 let this = Self {
250- basic_coverage_blocks,
251207 sorted_spans_iter : sorted_spans. into_iter ( ) ,
252208 some_curr : None ,
253209 some_prev : None ,
254- pending_dups : Vec :: new ( ) ,
255- refined_spans : Vec :: with_capacity ( basic_coverage_blocks. num_nodes ( ) * 2 ) ,
210+ refined_spans : Vec :: with_capacity ( sorted_spans_len) ,
256211 } ;
257212
258213 this. to_refined_spans ( )
@@ -292,21 +247,11 @@ impl<'a> SpansRefiner<'a> {
292247 self . take_curr ( ) ; // Discards curr.
293248 } else if curr. is_closure {
294249 self . carve_out_span_for_closure ( ) ;
295- } else if prev. original_span == prev. span && prev. span == curr. span {
296- // Prev and curr have the same span, and prev's span hasn't
297- // been modified by other spans.
298- self . update_pending_dups ( ) ;
299250 } else {
300251 self . cutoff_prev_at_overlapping_curr ( ) ;
301252 }
302253 }
303254
304- // Drain any remaining dups into the output.
305- for dup in self . pending_dups . drain ( ..) {
306- debug ! ( " ...adding at least one pending dup={:?}" , dup) ;
307- self . refined_spans . push ( dup. into_refined ( ) ) ;
308- }
309-
310255 // There is usually a final span remaining in `prev` after the loop ends,
311256 // so add it to the output as well.
312257 if let Some ( prev) = self . some_prev . take ( ) {
@@ -359,36 +304,6 @@ impl<'a> SpansRefiner<'a> {
359304 self . some_prev . take ( ) . unwrap_or_else ( || bug ! ( "some_prev is None (take_prev)" ) )
360305 }
361306
362- /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
363- /// `pending_dups` spans), then one of the following two things happened during the previous
364- /// iteration:
365- /// * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups
366- /// (in which case there should be at least two spans in `pending_dups`); or
367- /// * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case
368- /// `pending_dups` could have as few as one span)
369- /// In either case, no more spans will match the span of `pending_dups`, so
370- /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
371- fn maybe_flush_pending_dups ( & mut self ) {
372- let Some ( last_dup) = self . pending_dups . last ( ) else { return } ;
373- if last_dup. span == self . prev ( ) . span {
374- return ;
375- }
376-
377- debug ! (
378- " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
379- previous iteration, or prev started a new disjoint span"
380- ) ;
381- if last_dup. span . hi ( ) <= self . curr ( ) . span . lo ( ) {
382- for dup in self . pending_dups . drain ( ..) {
383- debug ! ( " ...adding at least one pending={:?}" , dup) ;
384- self . refined_spans . push ( dup. into_refined ( ) ) ;
385- }
386- } else {
387- self . pending_dups . clear ( ) ;
388- }
389- assert ! ( self . pending_dups. is_empty( ) ) ;
390- }
391-
392307 /// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order.
393308 fn next_coverage_span ( & mut self ) -> bool {
394309 if let Some ( curr) = self . some_curr . take ( ) {
@@ -408,7 +323,6 @@ impl<'a> SpansRefiner<'a> {
408323 ) ;
409324 } else {
410325 self . some_curr = Some ( CurrCovspan :: new ( curr. span , curr. bcb , curr. is_closure ) ) ;
411- self . maybe_flush_pending_dups ( ) ;
412326 return true ;
413327 }
414328 }
@@ -433,13 +347,6 @@ impl<'a> SpansRefiner<'a> {
433347 let mut pre_closure = self . prev ( ) . refined_copy ( ) ;
434348 pre_closure. span = pre_closure. span . with_hi ( left_cutoff) ;
435349 debug ! ( " prev overlaps a closure. Adding span for pre_closure={:?}" , pre_closure) ;
436-
437- for mut dup in self . pending_dups . iter ( ) . map ( DuplicateCovspan :: refined_copy) {
438- dup. span = dup. span . with_hi ( left_cutoff) ;
439- debug ! ( " ...and at least one pre_closure dup={:?}" , dup) ;
440- self . refined_spans . push ( dup) ;
441- }
442-
443350 self . refined_spans . push ( pre_closure) ;
444351 }
445352
@@ -448,58 +355,9 @@ impl<'a> SpansRefiner<'a> {
448355 self . prev_mut ( ) . span = self . prev ( ) . span . with_lo ( right_cutoff) ;
449356 debug ! ( " Mutated prev.span to start after the closure. prev={:?}" , self . prev( ) ) ;
450357
451- for dup in & mut self . pending_dups {
452- debug ! ( " ...and at least one overlapping dup={:?}" , dup) ;
453- dup. span = dup. span . with_lo ( right_cutoff) ;
454- }
455-
456358 // Prevent this curr from becoming prev.
457359 let closure_covspan = self . take_curr ( ) . into_refined ( ) ;
458360 self . refined_spans . push ( closure_covspan) ; // since self.prev() was already updated
459- } else {
460- self . pending_dups . clear ( ) ;
461- }
462- }
463-
464- /// Called if `curr.span` equals `prev.original_span` (and potentially equal to all
465- /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
466- /// If prev.span() was merged into other spans (with matching BCB, for instance),
467- /// `prev.span.hi()` will be greater than (further right of) `prev.original_span.hi()`.
468- /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
469- /// greater than prev.original_span.lo(). The actual span of `prev.original_span` is
470- /// not as important as knowing that `prev()` **used to have the same span** as `curr()`,
471- /// which means their sort order is still meaningful for determining the dominator
472- /// relationship.
473- ///
474- /// When two coverage spans have the same `Span`, dominated spans can be discarded; but if
475- /// neither coverage span dominates the other, both (or possibly more than two) are held,
476- /// until their disposition is determined. In this latter case, the `prev` dup is moved into
477- /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
478- fn update_pending_dups ( & mut self ) {
479- let prev_bcb = self . prev ( ) . bcb ;
480- let curr_bcb = self . curr ( ) . bcb ;
481-
482- // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
483- // impossible for `curr` to dominate any previous coverage span.
484- debug_assert ! ( !self . basic_coverage_blocks. dominates( curr_bcb, prev_bcb) ) ;
485-
486- // `prev` is a duplicate of `curr`, so add it to the list of pending dups.
487- // If it dominates `curr`, it will be removed by the subsequent discard step.
488- let prev = self . take_prev ( ) . into_dup ( ) ;
489- debug ! ( ?prev, "adding prev to pending dups" ) ;
490- self . pending_dups . push ( prev) ;
491-
492- let initial_pending_count = self . pending_dups . len ( ) ;
493- if initial_pending_count > 0 {
494- self . pending_dups
495- . retain ( |dup| !self . basic_coverage_blocks . dominates ( dup. bcb , curr_bcb) ) ;
496-
497- let n_discarded = initial_pending_count - self . pending_dups . len ( ) ;
498- if n_discarded > 0 {
499- debug ! (
500- " discarded {n_discarded} of {initial_pending_count} pending_dups that dominated curr" ,
501- ) ;
502- }
503361 }
504362 }
505363
@@ -516,19 +374,13 @@ impl<'a> SpansRefiner<'a> {
516374 if it has statements that end before curr; prev={:?}",
517375 self . prev( )
518376 ) ;
519- if self . pending_dups . is_empty ( ) {
520- let curr_span = self . curr ( ) . span ;
521- self . prev_mut ( ) . cutoff_statements_at ( curr_span. lo ( ) ) ;
522- if self . prev ( ) . merged_spans . is_empty ( ) {
523- debug ! ( " ... no non-overlapping statements to add" ) ;
524- } else {
525- debug ! ( " ... adding modified prev={:?}" , self . prev( ) ) ;
526- let prev = self . take_prev ( ) . into_refined ( ) ;
527- self . refined_spans . push ( prev) ;
528- }
377+
378+ let curr_span = self . curr ( ) . span ;
379+ if let Some ( prev) = self . take_prev ( ) . cutoff_statements_at ( curr_span. lo ( ) ) {
380+ debug ! ( "after cutoff, adding {prev:?}" ) ;
381+ self . refined_spans . push ( prev) ;
529382 } else {
530- // with `pending_dups`, `prev` cannot have any statements that don't overlap
531- self . pending_dups . clear ( ) ;
383+ debug ! ( "prev was eliminated by cutoff" ) ;
532384 }
533385 }
534386}
0 commit comments