@@ -61,7 +61,7 @@ pub(super) fn generate_coverage_spans(
61
61
hir_info,
62
62
basic_coverage_blocks,
63
63
) ;
64
- let coverage_spans = SpansRefiner :: refine_sorted_spans ( basic_coverage_blocks , sorted_spans) ;
64
+ let coverage_spans = SpansRefiner :: refine_sorted_spans ( sorted_spans) ;
65
65
mappings. extend ( coverage_spans. into_iter ( ) . map ( |RefinedCovspan { bcb, span, .. } | {
66
66
// Each span produced by the generator represents an ordinary code region.
67
67
BcbMapping { kind : BcbMappingKind :: Code ( bcb) , span }
@@ -88,8 +88,6 @@ pub(super) fn generate_coverage_spans(
88
88
89
89
#[ derive( Debug ) ]
90
90
struct CurrCovspan {
91
- /// This is used as the basis for [`PrevCovspan::original_span`], so it must
92
- /// not be modified.
93
91
span : Span ,
94
92
bcb : BasicCoverageBlock ,
95
93
is_closure : bool ,
@@ -102,7 +100,7 @@ impl CurrCovspan {
102
100
103
101
fn into_prev ( self ) -> PrevCovspan {
104
102
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 }
106
104
}
107
105
108
106
fn into_refined ( self ) -> RefinedCovspan {
@@ -115,7 +113,6 @@ impl CurrCovspan {
115
113
116
114
#[ derive( Debug ) ]
117
115
struct PrevCovspan {
118
- original_span : Span ,
119
116
span : Span ,
120
117
bcb : BasicCoverageBlock ,
121
118
/// List of all the original spans from MIR that have been merged into this
@@ -135,42 +132,17 @@ impl PrevCovspan {
135
132
self . merged_spans . push ( other. span ) ;
136
133
}
137
134
138
- fn cutoff_statements_at ( & mut self , cutoff_pos : BytePos ) {
135
+ fn cutoff_statements_at ( mut self , cutoff_pos : BytePos ) -> Option < RefinedCovspan > {
139
136
self . merged_spans . retain ( |span| span. hi ( ) <= cutoff_pos) ;
140
137
if let Some ( max_hi) = self . merged_spans . iter ( ) . map ( |span| span. hi ( ) ) . max ( ) {
141
138
self . span = self . span . with_hi ( max_hi) ;
142
139
}
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
- }
156
140
157
- fn into_refined ( self ) -> RefinedCovspan {
158
- self . refined_copy ( )
141
+ if self . merged_spans . is_empty ( ) { None } else { Some ( self . into_refined ( ) ) }
159
142
}
160
- }
161
-
162
- #[ derive( Debug ) ]
163
- struct DuplicateCovspan {
164
- span : Span ,
165
- bcb : BasicCoverageBlock ,
166
- is_closure : bool ,
167
- }
168
143
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.
172
144
fn refined_copy ( & self ) -> RefinedCovspan {
173
- let & Self { span, bcb, is_closure } = self ;
145
+ let & Self { span, bcb, merged_spans : _ , is_closure } = self ;
174
146
RefinedCovspan { span, bcb, is_closure }
175
147
}
176
148
@@ -205,10 +177,7 @@ impl RefinedCovspan {
205
177
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
206
178
/// execution
207
179
/// * 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 {
212
181
/// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
213
182
/// dominance between the `BasicCoverageBlock`s of equal `Span`s.
214
183
sorted_spans_iter : std:: vec:: IntoIter < SpanFromMir > ,
@@ -223,36 +192,22 @@ struct SpansRefiner<'a> {
223
192
/// If that `curr` was discarded, `prev` retains its value from the previous iteration.
224
193
some_prev : Option < PrevCovspan > ,
225
194
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
-
236
195
/// The final coverage spans to add to the coverage map. A `Counter` or `Expression`
237
196
/// will also be injected into the MIR for each BCB that has associated spans.
238
197
refined_spans : Vec < RefinedCovspan > ,
239
198
}
240
199
241
- impl < ' a > SpansRefiner < ' a > {
200
+ impl SpansRefiner {
242
201
/// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
243
202
/// them by merging compatible adjacent spans, removing redundant spans,
244
203
/// 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 ( ) ;
249
206
let this = Self {
250
- basic_coverage_blocks,
251
207
sorted_spans_iter : sorted_spans. into_iter ( ) ,
252
208
some_curr : None ,
253
209
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) ,
256
211
} ;
257
212
258
213
this. to_refined_spans ( )
@@ -292,21 +247,11 @@ impl<'a> SpansRefiner<'a> {
292
247
self . take_curr ( ) ; // Discards curr.
293
248
} else if curr. is_closure {
294
249
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 ( ) ;
299
250
} else {
300
251
self . cutoff_prev_at_overlapping_curr ( ) ;
301
252
}
302
253
}
303
254
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
-
310
255
// There is usually a final span remaining in `prev` after the loop ends,
311
256
// so add it to the output as well.
312
257
if let Some ( prev) = self . some_prev . take ( ) {
@@ -359,36 +304,6 @@ impl<'a> SpansRefiner<'a> {
359
304
self . some_prev . take ( ) . unwrap_or_else ( || bug ! ( "some_prev is None (take_prev)" ) )
360
305
}
361
306
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
-
392
307
/// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order.
393
308
fn next_coverage_span ( & mut self ) -> bool {
394
309
if let Some ( curr) = self . some_curr . take ( ) {
@@ -408,7 +323,6 @@ impl<'a> SpansRefiner<'a> {
408
323
) ;
409
324
} else {
410
325
self . some_curr = Some ( CurrCovspan :: new ( curr. span , curr. bcb , curr. is_closure ) ) ;
411
- self . maybe_flush_pending_dups ( ) ;
412
326
return true ;
413
327
}
414
328
}
@@ -433,13 +347,6 @@ impl<'a> SpansRefiner<'a> {
433
347
let mut pre_closure = self . prev ( ) . refined_copy ( ) ;
434
348
pre_closure. span = pre_closure. span . with_hi ( left_cutoff) ;
435
349
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
-
443
350
self . refined_spans . push ( pre_closure) ;
444
351
}
445
352
@@ -448,58 +355,9 @@ impl<'a> SpansRefiner<'a> {
448
355
self . prev_mut ( ) . span = self . prev ( ) . span . with_lo ( right_cutoff) ;
449
356
debug ! ( " Mutated prev.span to start after the closure. prev={:?}" , self . prev( ) ) ;
450
357
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
-
456
358
// Prevent this curr from becoming prev.
457
359
let closure_covspan = self . take_curr ( ) . into_refined ( ) ;
458
360
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
- }
503
361
}
504
362
}
505
363
@@ -516,19 +374,13 @@ impl<'a> SpansRefiner<'a> {
516
374
if it has statements that end before curr; prev={:?}",
517
375
self . prev( )
518
376
) ;
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) ;
529
382
} 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" ) ;
532
384
}
533
385
}
534
386
}
0 commit comments