consolidate and use `find_sub_region_live_at` for everything

remove the old blame system
This commit is contained in:
Niko Matsakis 2018-07-23 22:03:08 +03:00
parent 078220daa8
commit 92786a48f8
4 changed files with 47 additions and 96 deletions

View File

@ -54,7 +54,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
borrow_region_vid
);
let region_sub = regioncx.find_constraint(borrow_region_vid, context.loc);
let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc);
debug!(
"explain_why_borrow_contains_point: region_sub={:?}",

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use borrow_check::nll::region_infer::values::ToElementIndex;
use borrow_check::nll::region_infer::{ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
@ -75,11 +74,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir: &Mir<'tcx>,
from_region: RegionVid,
target_test: impl Fn(RegionVid) -> bool,
) -> (ConstraintCategory, Span) {
) -> (ConstraintCategory, Span, RegionVid) {
debug!("best_blame_constraint(from_region={:?})", from_region);
// Find all paths
let path = self
let (path, target_region) = self
.find_constraint_paths_between_regions(from_region, target_test)
.unwrap();
debug!("best_blame_constraint: path={:#?}", path);
@ -98,7 +97,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
debug!("best_blame_constraint: sorted_path={:?}", categorized_path);
*categorized_path.first().unwrap()
let &(category, span) = categorized_path.first().unwrap();
(category, span, target_region)
}
/// Walks the graph of constraints (where `'a: 'b` is considered
@ -106,11 +107,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// `to_region`. The paths are accumulated into the vector
/// `results`. The paths are stored as a series of
/// `ConstraintIndex` values -- in other words, a list of *edges*.
///
/// Returns: a series of constraints as well as the region `R`
/// that passed the target test.
fn find_constraint_paths_between_regions(
&self,
from_region: RegionVid,
target_test: impl Fn(RegionVid) -> bool,
) -> Option<Vec<ConstraintIndex>> {
) -> Option<(Vec<ConstraintIndex>, RegionVid)> {
let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
context[from_region] = Trace::StartRegion;
@ -138,7 +142,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
Trace::StartRegion => {
result.reverse();
return Some(result);
return Some((result, r));
}
}
}
@ -253,7 +257,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
) {
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
let (category, span) = self.best_blame_constraint(mir, fr, |r| r == outlived_fr);
let (category, span, _) = self.best_blame_constraint(mir, fr, |r| r == outlived_fr);
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
@ -393,82 +397,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
diag.buffer(errors_buffer);
}
// Find some constraint `X: Y` where:
// - `fr1: X` transitively
// - and `Y` is live at `elem`
crate fn find_constraint(&self, fr1: RegionVid, elem: Location) -> RegionVid {
let index = self.blame_constraint(fr1, elem);
self.constraints[index].sub
}
/// Tries to finds a good span to blame for the fact that `fr1`
/// contains `fr2`.
pub(super) fn blame_constraint(
&self,
fr1: RegionVid,
elem: impl ToElementIndex,
) -> ConstraintIndex {
// Find everything that influenced final value of `fr`.
let influenced_fr1 = self.dependencies(fr1);
// Try to find some outlives constraint `'X: fr2` where `'X`
// influenced `fr1`. Blame that.
//
// NB, this is a pretty bad choice most of the time. In
// particular, the connection between `'X` and `fr1` may not
// be obvious to the user -- not to mention the naive notion
// of dependencies, which doesn't account for the locations of
// contraints at all. But it will do for now.
let relevant_constraint = self.constraints
.iter_enumerated()
.filter_map(|(i, constraint)| {
if !self.liveness_constraints.contains(constraint.sub, elem) {
None
} else {
influenced_fr1[constraint.sup]
.map(|distance| (distance, i))
}
// Finds some region R such that `fr1: R` and `R` is live at
// `elem`.
crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
// Find all paths
let (_path, r) = self
.find_constraint_paths_between_regions(fr1, |r| {
self.liveness_constraints.contains(r, elem)
})
.min() // constraining fr1 with fewer hops *ought* to be more obvious
.map(|(_dist, i)| i);
relevant_constraint.unwrap_or_else(|| {
bug!(
"could not find any constraint to blame for {:?}: {:?}",
fr1,
elem,
);
})
.unwrap();
r
}
/// Finds all regions whose values `'a` may depend on in some way.
/// For each region, returns either `None` (does not influence
/// `'a`) or `Some(d)` which indicates that it influences `'a`
/// with distinct `d` (minimum number of edges that must be
/// traversed).
///
/// Used during error reporting, extremely naive and inefficient.
fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
let mut result_set = IndexVec::from_elem(None, &self.definitions);
let mut changed = true;
result_set[r0] = Some(0); // distance 0 from `r0`
while changed {
changed = false;
for constraint in self.constraints.iter() {
if let Some(n) = result_set[constraint.sup] {
let m = n + 1;
if result_set[constraint.sub]
.map(|distance| m < distance)
.unwrap_or(true)
{
result_set[constraint.sub] = Some(m);
changed = true;
}
}
}
}
result_set
// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
crate fn find_outlives_blame_span(&self, mir: &Mir<'tcx>, fr1: RegionVid, fr2: RegionVid) -> Span {
let (_, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
span
}
}

View File

@ -884,8 +884,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
longer_fr, shorter_fr,
);
let blame_index = self.blame_constraint(longer_fr, shorter_fr);
let blame_span = self.constraints[blame_index].locations.span(mir);
let blame_span = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
// Shrink `fr` until we find a non-local region (if we do).

View File

@ -2,28 +2,37 @@ error[E0499]: cannot borrow `*arg` as mutable more than once at a time
--> $DIR/mut-borrow-in-loop.rs:20:25
|
LL | (self.func)(arg) //~ ERROR cannot borrow
| ------------^^^-
| | |
| | mutable borrow starts here in previous iteration of loop
| borrow later used here
| ^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
--> $DIR/mut-borrow-in-loop.rs:17:6
|
LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
| ^^
error[E0499]: cannot borrow `*arg` as mutable more than once at a time
--> $DIR/mut-borrow-in-loop.rs:26:25
|
LL | (self.func)(arg) //~ ERROR cannot borrow
| ------------^^^-
| | |
| | mutable borrow starts here in previous iteration of loop
| borrow later used here
| ^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
--> $DIR/mut-borrow-in-loop.rs:17:6
|
LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
| ^^
error[E0499]: cannot borrow `*arg` as mutable more than once at a time
--> $DIR/mut-borrow-in-loop.rs:33:25
|
LL | (self.func)(arg) //~ ERROR cannot borrow
| ------------^^^-
| | |
| | mutable borrow starts here in previous iteration of loop
| borrow later used here
| ^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 17:6...
--> $DIR/mut-borrow-in-loop.rs:17:6
|
LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
| ^^
error: aborting due to 3 previous errors