提交 ed72950f 编写于 作者: N Niko Matsakis

rework causal tracking to explore outlives relationships

Instead of tracking the "cause" of each bit that gets added, try to
recover that by walking outlives relationships. This is currently
imprecise, since it ignores the "point" where the outlives relationship
is incurred -- but that's ok, since we're about to stop considering that
overall in a later commit. This does seem to affect one error message
negatively, I didn't dig *too* hard to find out why.
上级 1fb17aba
......@@ -10,7 +10,7 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
use borrow_check::nll::region_infer::{RegionCausalInfo, RegionInferenceContext};
use borrow_check::nll::region_infer::RegionInferenceContext;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
......@@ -248,7 +248,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
nonlexical_regioncx: regioncx,
used_mut: FxHashSet(),
used_mut_upvars: SmallVec::new(),
nonlexical_cause_info: None,
borrow_set,
dominators,
};
......@@ -367,7 +366,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
/// contains the results from region inference and lets us e.g.
/// find out which CFG points are contained in each borrow region.
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
nonlexical_cause_info: Option<RegionCausalInfo>,
/// The set of borrows extracted from the MIR
borrow_set: Rc<BorrowSet<'tcx>>,
......
......@@ -32,13 +32,9 @@ pub(in borrow_check) fn explain_why_borrow_contains_point(
let regioncx = &&self.nonlexical_regioncx;
let mir = self.mir;
if self.nonlexical_cause_info.is_none() {
self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
}
let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
match *cause.root_cause() {
let borrow_region_vid = regioncx.to_region_vid(borrow.region);
if let Some(cause) = regioncx.why_region_contains_point(borrow_region_vid, context.loc) {
match cause {
Cause::LiveVar(local, location) => {
match find_regular_use(mir, regioncx, borrow, location, local) {
Some(p) => {
......
......@@ -101,7 +101,7 @@ struct RegionDefinition<'tcx> {
/// NB: The variants in `Cause` are intentionally ordered. Lower
/// values are preferred when it comes to error messages. Do not
/// reorder willy nilly.
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum Cause {
/// point inserted because Local was live at the given Location
LiveVar(Local, Location),
......@@ -115,23 +115,6 @@ pub(crate) enum Cause {
/// part of the initial set of values for a universally quantified region
UniversalRegion(RegionVid),
/// Element E was added to R because there was some
/// outlives obligation `R: R1 @ P` and `R1` contained `E`.
Outlives {
/// the reason that R1 had E
original_cause: Rc<Cause>,
/// the point P from the relation
constraint_location: Location,
/// The span indicating why we added the outlives constraint.
constraint_span: Span,
},
}
pub(crate) struct RegionCausalInfo {
inferred_values: RegionValues,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
......@@ -477,21 +460,13 @@ fn solve_inner<'gcx>(
}
}
/// Re-execute the region inference, this time tracking causal information.
/// This is significantly slower, so it is done only when an error is being reported.
pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
let dfs_storage = &mut self.new_dfs_storage();
let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(true));
RegionCausalInfo { inferred_values }
}
/// Propagate the region constraints: this will grow the values
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
fn propagate_constraints(&mut self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage) {
self.dependency_map = Some(self.build_dependency_map());
let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(false));
let inferred_values = self.compute_region_values(mir, dfs_storage);
self.inferred_values = Some(inferred_values);
}
......@@ -500,7 +475,6 @@ fn compute_region_values(
&self,
mir: &Mir<'tcx>,
dfs_storage: &mut dfs::DfsStorage,
track_causes: TrackCauses,
) -> RegionValues {
debug!("compute_region_values()");
debug!("compute_region_values: constraints={:#?}", {
......@@ -511,7 +485,7 @@ fn compute_region_values(
// The initial values for each region are derived from the liveness
// constraints we have accumulated.
let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
let mut inferred_values = self.liveness_constraints.duplicate(TrackCauses(false));
let dependency_map = self.dependency_map.as_ref().unwrap();
......@@ -1095,6 +1069,17 @@ fn report_error(
diag.emit();
}
crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
// Find some constraint `X: Y` where:
// - `fr1: X` transitively
// - and `Y` is live at `elem`
let index = self.blame_constraint(fr1, elem);
let region_sub = self.constraints[index].sub;
// then return why `Y` was live at `elem`
self.liveness_constraints.cause(region_sub, elem)
}
/// Tries to finds a good span to blame for the fact that `fr1`
/// contains `fr2`.
fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex {
......@@ -1112,7 +1097,7 @@ fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> Constra
let relevant_constraint = self.constraints
.iter_enumerated()
.filter_map(|(i, constraint)| {
if self.liveness_constraints.contains(constraint.sub, elem) {
if !self.liveness_constraints.contains(constraint.sub, elem) {
None
} else {
influenced_fr1[constraint.sup]
......@@ -1163,16 +1148,6 @@ fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
}
}
impl RegionCausalInfo {
/// Returns the *reason* that the region `r` contains the given point.
pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
where
R: ToRegionVid,
{
self.inferred_values.cause(r.to_region_vid(), p)
}
}
impl<'tcx> RegionDefinition<'tcx> {
fn new(origin: RegionVariableOrigin) -> Self {
// Create a new region definition. Note that, for free
......@@ -1316,31 +1291,3 @@ fn subst_closure_mapping<T>(
})
}
}
trait CauseExt {
fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause;
}
impl CauseExt for Rc<Cause> {
/// Creates a derived cause due to an outlives constraint.
fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause {
Cause::Outlives {
original_cause: self.clone(),
constraint_location,
constraint_span,
}
}
}
impl Cause {
pub(crate) fn root_cause(&self) -> &Cause {
match self {
Cause::LiveVar(..)
| Cause::DropVar(..)
| Cause::LiveOther(..)
| Cause::UniversalRegion(..) => self,
Cause::Outlives { original_cause, .. } => original_cause.root_cause(),
}
}
}
......@@ -8,17 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use borrow_check::nll::region_infer::TrackCauses;
use rustc_data_structures::bitvec::SparseBitMatrix;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::ty::{self, RegionVid};
use rustc::ty::RegionVid;
use std::fmt::Debug;
use std::rc::Rc;
use syntax::codemap::Span;
use super::{Cause, CauseExt, TrackCauses};
use super::Cause;
/// Maps between the various kinds of elements of a region value to
/// the internal indices that w use.
......@@ -196,7 +197,7 @@ pub(super) struct RegionValues {
causes: Option<CauseMap>,
}
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Cause>;
impl RegionValues {
/// Creates a new set of "region values" that tracks causal information.
......@@ -255,7 +256,7 @@ fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F
debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i));
if let Some(causes) = &mut self.causes {
let cause = Rc::new(make_cause(causes));
let cause = make_cause(causes);
causes.insert((r, i), cause);
}
......@@ -267,15 +268,8 @@ fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F
// #49998: compare using root cause alone to avoid
// useless traffic from similar outlives chains.
let overwrite = if ty::tls::with(|tcx| {
tcx.sess.opts.debugging_opts.nll_subminimal_causes
}) {
cause.root_cause() < old_cause.root_cause()
} else {
cause < **old_cause
};
if overwrite {
*old_cause = Rc::new(cause);
if cause < *old_cause {
*old_cause = cause;
return true;
}
}
......@@ -294,13 +288,11 @@ pub(super) fn add_due_to_outlives<T: ToElementIndex>(
from_region: RegionVid,
to_region: RegionVid,
elem: T,
constraint_location: Location,
constraint_span: Span,
_constraint_location: Location,
_constraint_span: Span,
) -> bool {
let elem = self.elements.index(elem);
self.add_internal(to_region, elem, |causes| {
causes[&(from_region, elem)].outlives(constraint_location, constraint_span)
})
self.add_internal(to_region, elem, |causes| causes[&(from_region, elem)])
}
/// Adds all the universal regions outlived by `from_region` to
......@@ -445,7 +437,7 @@ fn push_location_range(str: &mut String, location1: Location, location2: Locatio
///
/// Returns None if cause tracking is disabled or `elem` is not
/// actually found in `r`.
pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Rc<Cause>> {
pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Cause> {
let index = self.elements.index(elem);
if let Some(causes) = &self.causes {
causes.get(&(r, index)).cloned()
......
......@@ -2,19 +2,28 @@ 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
| ------------^^^-
| | |
| | mutable borrow starts here in previous iteration of loop
| borrow later used here
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
| ------------^^^-
| | |
| | mutable borrow starts here in previous iteration of loop
| borrow later used here
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
| ------------^^^-
| | |
| | mutable borrow starts here in previous iteration of loop
| borrow later used here
error: aborting due to 3 previous errors
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册