Skip to content

Commit 88ade9c

Browse files
committed
coverage: Eagerly convert coverage spans to a simpler form
1 parent bf74fb1 commit 88ade9c

File tree

2 files changed

+55
-49
lines changed

2 files changed

+55
-49
lines changed

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ pub(super) fn extract_refined_covspans(
2828
let ExtractedCovspans { mut covspans, mut holes } =
2929
extract_covspans_and_holes_from_mir(mir_body, hir_info, basic_coverage_blocks);
3030

31+
// First, perform the passes that need macro information.
3132
covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb));
3233
remove_unwanted_macro_spans(&mut covspans);
3334
split_visible_macro_spans(&mut covspans);
3435

35-
let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| {
36+
// We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`.
37+
let mut covspans = covspans.into_iter().map(SpanFromMir::into_covspan).collect::<Vec<_>>();
38+
39+
let compare_covspans = |a: &Covspan, b: &Covspan| {
3640
compare_spans(a.span, b.span)
3741
// After deduplication, we want to keep only the most-dominated BCB.
3842
.then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse())
@@ -53,7 +57,7 @@ pub(super) fn extract_refined_covspans(
5357
// and grouping them in buckets separated by the holes.
5458

5559
let mut input_covspans = VecDeque::from(covspans);
56-
let mut fragments: Vec<SpanFromMir> = vec![];
60+
let mut fragments = vec![];
5761

5862
// For each hole:
5963
// - Identify the spans that are entirely or partly before the hole.
@@ -88,7 +92,7 @@ pub(super) fn extract_refined_covspans(
8892
covspans.sort_by(compare_covspans);
8993

9094
let covspans = refine_sorted_spans(covspans);
91-
code_mappings.extend(covspans.into_iter().map(|RefinedCovspan { span, bcb }| {
95+
code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| {
9296
// Each span produced by the refiner represents an ordinary code region.
9397
mappings::CodeMapping { span, bcb }
9498
}));
@@ -145,23 +149,6 @@ fn split_visible_macro_spans(covspans: &mut Vec<SpanFromMir>) {
145149
covspans.extend(extra_spans);
146150
}
147151

148-
#[derive(Debug)]
149-
struct RefinedCovspan {
150-
span: Span,
151-
bcb: BasicCoverageBlock,
152-
}
153-
154-
impl RefinedCovspan {
155-
fn is_mergeable(&self, other: &Self) -> bool {
156-
self.bcb == other.bcb
157-
}
158-
159-
fn merge_from(&mut self, other: &Self) {
160-
debug_assert!(self.is_mergeable(other));
161-
self.span = self.span.to(other.span);
162-
}
163-
}
164-
165152
/// Similar to `.drain(..)`, but stops just before it would remove an item not
166153
/// satisfying the predicate.
167154
fn drain_front_while<'a, T>(
@@ -175,18 +162,18 @@ fn drain_front_while<'a, T>(
175162
/// those spans by removing spans that overlap in unwanted ways, and by merging
176163
/// compatible adjacent spans.
177164
#[instrument(level = "debug")]
178-
fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
165+
fn refine_sorted_spans(sorted_spans: Vec<Covspan>) -> Vec<Covspan> {
179166
// Holds spans that have been read from the input vector, but haven't yet
180167
// been committed to the output vector.
181168
let mut pending = vec![];
182169
let mut refined = vec![];
183170

184171
for curr in sorted_spans {
185-
pending.retain(|prev: &SpanFromMir| {
172+
pending.retain(|prev: &Covspan| {
186173
if prev.span.hi() <= curr.span.lo() {
187174
// There's no overlap between the previous/current covspans,
188175
// so move the previous one into the refined list.
189-
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
176+
refined.push(prev.clone());
190177
false
191178
} else {
192179
// Otherwise, retain the previous covspan only if it has the
@@ -199,26 +186,55 @@ fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
199186
}
200187

201188
// Drain the rest of the pending list into the refined list.
202-
for prev in pending {
203-
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
204-
}
189+
refined.extend(pending);
205190

206191
// Do one last merge pass, to simplify the output.
207192
debug!(?refined, "before merge");
208-
refined.dedup_by(|b, a| {
209-
if a.is_mergeable(b) {
210-
debug!(?a, ?b, "merging list-adjacent refined spans");
211-
a.merge_from(b);
212-
true
213-
} else {
214-
false
215-
}
216-
});
193+
refined.dedup_by(|b, a| a.merge_if_eligible(b));
217194
debug!(?refined, "after merge");
218195

219196
refined
220197
}
221198

199+
#[derive(Clone, Debug)]
200+
struct Covspan {
201+
span: Span,
202+
bcb: BasicCoverageBlock,
203+
}
204+
205+
impl Covspan {
206+
/// Splits this covspan into 0-2 parts:
207+
/// - The part that is strictly before the hole span, if any.
208+
/// - The part that is strictly after the hole span, if any.
209+
fn split_around_hole_span(&self, hole_span: Span) -> (Option<Self>, Option<Self>) {
210+
let before = try {
211+
let span = self.span.trim_end(hole_span)?;
212+
Self { span, ..*self }
213+
};
214+
let after = try {
215+
let span = self.span.trim_start(hole_span)?;
216+
Self { span, ..*self }
217+
};
218+
219+
(before, after)
220+
}
221+
222+
/// If `self` and `other` can be merged (i.e. they have the same BCB),
223+
/// mutates `self.span` to also include `other.span` and returns true.
224+
///
225+
/// Note that compatible covspans can be merged even if their underlying
226+
/// spans are not overlapping/adjacent; any space between them will also be
227+
/// part of the merged covspan.
228+
fn merge_if_eligible(&mut self, other: &Self) -> bool {
229+
if self.bcb != other.bcb {
230+
return false;
231+
}
232+
233+
self.span = self.span.to(other.span);
234+
true
235+
}
236+
}
237+
222238
/// Compares two spans in (lo ascending, hi descending) order.
223239
fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering {
224240
// First sort by span start.

compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
99
use crate::coverage::graph::{
1010
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
1111
};
12+
use crate::coverage::spans::Covspan;
1213
use crate::coverage::ExtractedHirInfo;
1314

1415
pub(crate) struct ExtractedCovspans {
@@ -306,19 +307,8 @@ impl SpanFromMir {
306307
Self { span, visible_macro, bcb }
307308
}
308309

309-
/// Splits this span into 0-2 parts:
310-
/// - The part that is strictly before the hole span, if any.
311-
/// - The part that is strictly after the hole span, if any.
312-
pub(crate) fn split_around_hole_span(&self, hole_span: Span) -> (Option<Self>, Option<Self>) {
313-
let before = try {
314-
let span = self.span.trim_end(hole_span)?;
315-
Self { span, ..*self }
316-
};
317-
let after = try {
318-
let span = self.span.trim_start(hole_span)?;
319-
Self { span, ..*self }
320-
};
321-
322-
(before, after)
310+
pub(crate) fn into_covspan(self) -> Covspan {
311+
let Self { span, visible_macro: _, bcb } = self;
312+
Covspan { span, bcb }
323313
}
324314
}

0 commit comments

Comments
 (0)