coverage: Rename is_closure
to is_hole
When refining covspans, we don't specifically care which ones represent closures; we just want to know which ones represent "holes" that should be carved out of other spans and then discarded. (Closures are currently the only source of hole spans, but in the future we might want to also create hole spans for nested items and inactive `#[cfg(..)]` regions.)
This commit is contained in:
parent
8bd33e332b
commit
44c8f55a6b
2 changed files with 58 additions and 59 deletions
|
@ -90,23 +90,23 @@ pub(super) fn generate_coverage_spans(
|
||||||
struct CurrCovspan {
|
struct CurrCovspan {
|
||||||
span: Span,
|
span: Span,
|
||||||
bcb: BasicCoverageBlock,
|
bcb: BasicCoverageBlock,
|
||||||
is_closure: bool,
|
is_hole: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurrCovspan {
|
impl CurrCovspan {
|
||||||
fn new(span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self {
|
fn new(span: Span, bcb: BasicCoverageBlock, is_hole: bool) -> Self {
|
||||||
Self { span, bcb, is_closure }
|
Self { span, bcb, is_hole }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_prev(self) -> PrevCovspan {
|
fn into_prev(self) -> PrevCovspan {
|
||||||
let Self { span, bcb, is_closure } = self;
|
let Self { span, bcb, is_hole } = self;
|
||||||
PrevCovspan { span, bcb, merged_spans: vec![span], is_closure }
|
PrevCovspan { span, bcb, merged_spans: vec![span], is_hole }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_refined(self) -> RefinedCovspan {
|
fn into_refined(self) -> RefinedCovspan {
|
||||||
// This is only called in cases where `curr` is a closure span that has
|
// This is only called in cases where `curr` is a hole span that has
|
||||||
// been carved out of `prev`.
|
// been carved out of `prev`.
|
||||||
debug_assert!(self.is_closure);
|
debug_assert!(self.is_hole);
|
||||||
self.into_prev().into_refined()
|
self.into_prev().into_refined()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,12 +118,12 @@ struct PrevCovspan {
|
||||||
/// List of all the original spans from MIR that have been merged into this
|
/// List of all the original spans from MIR that have been merged into this
|
||||||
/// span. Mainly used to precisely skip over gaps when truncating a span.
|
/// span. Mainly used to precisely skip over gaps when truncating a span.
|
||||||
merged_spans: Vec<Span>,
|
merged_spans: Vec<Span>,
|
||||||
is_closure: bool,
|
is_hole: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrevCovspan {
|
impl PrevCovspan {
|
||||||
fn is_mergeable(&self, other: &CurrCovspan) -> bool {
|
fn is_mergeable(&self, other: &CurrCovspan) -> bool {
|
||||||
self.bcb == other.bcb && !self.is_closure && !other.is_closure
|
self.bcb == other.bcb && !self.is_hole && !other.is_hole
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_from(&mut self, other: &CurrCovspan) {
|
fn merge_from(&mut self, other: &CurrCovspan) {
|
||||||
|
@ -142,8 +142,8 @@ impl PrevCovspan {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refined_copy(&self) -> RefinedCovspan {
|
fn refined_copy(&self) -> RefinedCovspan {
|
||||||
let &Self { span, bcb, merged_spans: _, is_closure } = self;
|
let &Self { span, bcb, merged_spans: _, is_hole } = self;
|
||||||
RefinedCovspan { span, bcb, is_closure }
|
RefinedCovspan { span, bcb, is_hole }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_refined(self) -> RefinedCovspan {
|
fn into_refined(self) -> RefinedCovspan {
|
||||||
|
@ -156,12 +156,12 @@ impl PrevCovspan {
|
||||||
struct RefinedCovspan {
|
struct RefinedCovspan {
|
||||||
span: Span,
|
span: Span,
|
||||||
bcb: BasicCoverageBlock,
|
bcb: BasicCoverageBlock,
|
||||||
is_closure: bool,
|
is_hole: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RefinedCovspan {
|
impl RefinedCovspan {
|
||||||
fn is_mergeable(&self, other: &Self) -> bool {
|
fn is_mergeable(&self, other: &Self) -> bool {
|
||||||
self.bcb == other.bcb && !self.is_closure && !other.is_closure
|
self.bcb == other.bcb && !self.is_hole && !other.is_hole
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_from(&mut self, other: &Self) {
|
fn merge_from(&mut self, other: &Self) {
|
||||||
|
@ -176,7 +176,8 @@ impl RefinedCovspan {
|
||||||
/// * Remove duplicate source code coverage regions
|
/// * Remove duplicate source code coverage regions
|
||||||
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
|
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
|
||||||
/// execution
|
/// execution
|
||||||
/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
|
/// * Carve out (leave uncovered) any "hole" spans that need to be left blank
|
||||||
|
/// (e.g. closures that will be counted by their own MIR body)
|
||||||
struct SpansRefiner {
|
struct SpansRefiner {
|
||||||
/// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
|
/// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
|
||||||
/// dominance between the `BasicCoverageBlock`s of equal `Span`s.
|
/// dominance between the `BasicCoverageBlock`s of equal `Span`s.
|
||||||
|
@ -228,7 +229,7 @@ impl SpansRefiner {
|
||||||
let curr = self.curr();
|
let curr = self.curr();
|
||||||
|
|
||||||
if prev.is_mergeable(curr) {
|
if prev.is_mergeable(curr) {
|
||||||
debug!(" same bcb (and neither is a closure), merge with prev={prev:?}");
|
debug!(?prev, "curr will be merged into prev");
|
||||||
let curr = self.take_curr();
|
let curr = self.take_curr();
|
||||||
self.prev_mut().merge_from(&curr);
|
self.prev_mut().merge_from(&curr);
|
||||||
} else if prev.span.hi() <= curr.span.lo() {
|
} else if prev.span.hi() <= curr.span.lo() {
|
||||||
|
@ -237,15 +238,13 @@ impl SpansRefiner {
|
||||||
);
|
);
|
||||||
let prev = self.take_prev().into_refined();
|
let prev = self.take_prev().into_refined();
|
||||||
self.refined_spans.push(prev);
|
self.refined_spans.push(prev);
|
||||||
} else if prev.is_closure {
|
} else if prev.is_hole {
|
||||||
// drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
|
// drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
|
||||||
// next iter
|
// next iter
|
||||||
debug!(
|
debug!(?prev, "prev (a hole) overlaps curr, so discarding curr");
|
||||||
" curr overlaps a closure (prev). Drop curr and keep prev for next iter. prev={prev:?}",
|
|
||||||
);
|
|
||||||
self.take_curr(); // Discards curr.
|
self.take_curr(); // Discards curr.
|
||||||
} else if curr.is_closure {
|
} else if curr.is_hole {
|
||||||
self.carve_out_span_for_closure();
|
self.carve_out_span_for_hole();
|
||||||
} else {
|
} else {
|
||||||
self.cutoff_prev_at_overlapping_curr();
|
self.cutoff_prev_at_overlapping_curr();
|
||||||
}
|
}
|
||||||
|
@ -269,10 +268,9 @@ impl SpansRefiner {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove spans derived from closures, originally added to ensure the coverage
|
// Discard hole spans, since their purpose was to carve out chunks from
|
||||||
// regions for the current function leave room for the closure's own coverage regions
|
// other spans, but we don't want the holes themselves in the final mappings.
|
||||||
// (injected separately, from the closure's own MIR).
|
self.refined_spans.retain(|covspan| !covspan.is_hole);
|
||||||
self.refined_spans.retain(|covspan| !covspan.is_closure);
|
|
||||||
self.refined_spans
|
self.refined_spans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,47 +313,43 @@ impl SpansRefiner {
|
||||||
{
|
{
|
||||||
// Skip curr because prev has already advanced beyond the end of curr.
|
// Skip curr because prev has already advanced beyond the end of curr.
|
||||||
// This can only happen if a prior iteration updated `prev` to skip past
|
// This can only happen if a prior iteration updated `prev` to skip past
|
||||||
// a region of code, such as skipping past a closure.
|
// a region of code, such as skipping past a hole.
|
||||||
debug!(
|
debug!(?prev, "prev.span starts after curr.span, so curr will be dropped");
|
||||||
" prev.span starts after curr.span, so curr will be dropped (skipping past \
|
|
||||||
closure?); prev={prev:?}",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_closure));
|
self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_hole));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
|
/// If `prev`s span extends left of the hole (`curr`), carve out the hole's span from
|
||||||
/// `prev`'s span. (The closure's coverage counters will be injected when processing the
|
/// `prev`'s span. Add the portion of the span to the left of the hole; and if the span
|
||||||
/// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
|
/// extends to the right of the hole, update `prev` to that portion of the span.
|
||||||
/// extends to the right of the closure, update `prev` to that portion of the span.
|
fn carve_out_span_for_hole(&mut self) {
|
||||||
fn carve_out_span_for_closure(&mut self) {
|
|
||||||
let prev = self.prev();
|
let prev = self.prev();
|
||||||
let curr = self.curr();
|
let curr = self.curr();
|
||||||
|
|
||||||
let left_cutoff = curr.span.lo();
|
let left_cutoff = curr.span.lo();
|
||||||
let right_cutoff = curr.span.hi();
|
let right_cutoff = curr.span.hi();
|
||||||
let has_pre_closure_span = prev.span.lo() < right_cutoff;
|
let has_pre_hole_span = prev.span.lo() < right_cutoff;
|
||||||
let has_post_closure_span = prev.span.hi() > right_cutoff;
|
let has_post_hole_span = prev.span.hi() > right_cutoff;
|
||||||
|
|
||||||
if has_pre_closure_span {
|
if has_pre_hole_span {
|
||||||
let mut pre_closure = self.prev().refined_copy();
|
let mut pre_hole = prev.refined_copy();
|
||||||
pre_closure.span = pre_closure.span.with_hi(left_cutoff);
|
pre_hole.span = pre_hole.span.with_hi(left_cutoff);
|
||||||
debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
|
debug!(?pre_hole, "prev overlaps a hole; adding pre-hole span");
|
||||||
self.refined_spans.push(pre_closure);
|
self.refined_spans.push(pre_hole);
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_post_closure_span {
|
if has_post_hole_span {
|
||||||
// Mutate `prev.span` to start after the closure (and discard curr).
|
// Mutate `prev.span` to start after the hole (and discard curr).
|
||||||
self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
|
self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
|
||||||
debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev());
|
debug!(prev=?self.prev(), "mutated prev to start after the hole");
|
||||||
|
|
||||||
// Prevent this curr from becoming prev.
|
// Prevent this curr from becoming prev.
|
||||||
let closure_covspan = self.take_curr().into_refined();
|
let hole_covspan = self.take_curr().into_refined();
|
||||||
self.refined_spans.push(closure_covspan); // since self.prev() was already updated
|
self.refined_spans.push(hole_covspan); // since self.prev() was already updated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,14 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
|
||||||
// - Span A extends further left, or
|
// - Span A extends further left, or
|
||||||
// - Both have the same start and span A extends further right
|
// - Both have the same start and span A extends further right
|
||||||
.then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse())
|
.then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse())
|
||||||
// If two spans have the same lo & hi, put closure spans first,
|
// If two spans have the same lo & hi, put hole spans first,
|
||||||
// as they take precedence over non-closure spans.
|
// as they take precedence over non-hole spans.
|
||||||
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
|
.then_with(|| Ord::cmp(&a.is_hole, &b.is_hole).reverse())
|
||||||
// After deduplication, we want to keep only the most-dominated BCB.
|
// After deduplication, we want to keep only the most-dominated BCB.
|
||||||
.then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse())
|
.then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse())
|
||||||
});
|
});
|
||||||
|
|
||||||
// Among covspans with the same span, keep only one. Closure spans take
|
// Among covspans with the same span, keep only one. Hole spans take
|
||||||
// precedence, otherwise keep the one with the most-dominated BCB.
|
// precedence, otherwise keep the one with the most-dominated BCB.
|
||||||
// (Ideally we should try to preserve _all_ non-dominating BCBs, but that
|
// (Ideally we should try to preserve _all_ non-dominating BCBs, but that
|
||||||
// requires a lot more complexity in the span refiner, for little benefit.)
|
// requires a lot more complexity in the span refiner, for little benefit.)
|
||||||
|
@ -78,8 +78,8 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
|
||||||
fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) {
|
fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) {
|
||||||
let mut seen_macro_spans = FxHashSet::default();
|
let mut seen_macro_spans = FxHashSet::default();
|
||||||
initial_spans.retain(|covspan| {
|
initial_spans.retain(|covspan| {
|
||||||
// Ignore (retain) closure spans and non-macro-expansion spans.
|
// Ignore (retain) hole spans and non-macro-expansion spans.
|
||||||
if covspan.is_closure || covspan.visible_macro.is_none() {
|
if covspan.is_hole || covspan.visible_macro.is_none() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) {
|
||||||
let mut extra_spans = vec![];
|
let mut extra_spans = vec![];
|
||||||
|
|
||||||
initial_spans.retain(|covspan| {
|
initial_spans.retain(|covspan| {
|
||||||
if covspan.is_closure {
|
if covspan.is_hole {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(!covspan.is_closure);
|
assert!(!covspan.is_hole);
|
||||||
extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb, false));
|
extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb, false));
|
||||||
extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb, false));
|
extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb, false));
|
||||||
false // Discard the original covspan that we just split.
|
false // Discard the original covspan that we just split.
|
||||||
|
@ -148,6 +148,8 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
|
||||||
let expn_span = filtered_statement_span(statement)?;
|
let expn_span = filtered_statement_span(statement)?;
|
||||||
let (span, visible_macro) = unexpand(expn_span)?;
|
let (span, visible_macro) = unexpand(expn_span)?;
|
||||||
|
|
||||||
|
// A statement that looks like the assignment of a closure expression
|
||||||
|
// is treated as a "hole" span, to be carved out of other spans.
|
||||||
Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement)))
|
Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement)))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -336,7 +338,10 @@ pub(super) struct SpanFromMir {
|
||||||
pub(super) span: Span,
|
pub(super) span: Span,
|
||||||
visible_macro: Option<Symbol>,
|
visible_macro: Option<Symbol>,
|
||||||
pub(super) bcb: BasicCoverageBlock,
|
pub(super) bcb: BasicCoverageBlock,
|
||||||
pub(super) is_closure: bool,
|
/// If true, this covspan represents a "hole" that should be carved out
|
||||||
|
/// from other spans, e.g. because it represents a closure expression that
|
||||||
|
/// will be instrumented separately as its own function.
|
||||||
|
pub(super) is_hole: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpanFromMir {
|
impl SpanFromMir {
|
||||||
|
@ -348,8 +353,8 @@ impl SpanFromMir {
|
||||||
span: Span,
|
span: Span,
|
||||||
visible_macro: Option<Symbol>,
|
visible_macro: Option<Symbol>,
|
||||||
bcb: BasicCoverageBlock,
|
bcb: BasicCoverageBlock,
|
||||||
is_closure: bool,
|
is_hole: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self { span, visible_macro, bcb, is_closure }
|
Self { span, visible_macro, bcb, is_hole }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue