mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 00:24:03 +00:00
Make causal tracking lazy
This commit is contained in:
parent
ec761903ec
commit
c85c5a0423
@ -138,9 +138,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.explain_span(scope_decorated_tag, span)
|
||||
}
|
||||
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => self.msg_span_from_free_region(region),
|
||||
|
||||
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
|
||||
self.msg_span_from_free_region(region)
|
||||
}
|
||||
|
||||
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
|
||||
|
||||
@ -175,6 +175,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
|
||||
match *region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
self.msg_span_from_early_bound_and_free_regions(region)
|
||||
},
|
||||
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn msg_span_from_early_bound_and_free_regions(
|
||||
self,
|
||||
region: ty::Region<'tcx>,
|
||||
) -> (String, Option<Span>) {
|
||||
let scope = region.free_region_binding_scope(self);
|
||||
let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
|
||||
let unknown;
|
||||
|
@ -124,6 +124,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let value_msg = match self.describe_place(place) {
|
||||
Some(name) => format!("`{}`", name),
|
||||
None => "value".to_owned(),
|
||||
@ -132,7 +133,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Some(name) => format!("`{}`", name),
|
||||
None => "value".to_owned(),
|
||||
};
|
||||
let mut err = self.tcx.cannot_move_when_borrowed(
|
||||
let mut err = tcx.cannot_move_when_borrowed(
|
||||
span,
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
Origin::Mir,
|
||||
@ -152,7 +153,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) {
|
||||
let mut err = self.tcx.cannot_use_when_mutably_borrowed(
|
||||
let tcx = self.tcx;
|
||||
let mut err = tcx.cannot_use_when_mutably_borrowed(
|
||||
span,
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
self.retrieve_borrow_span(borrow),
|
||||
@ -254,6 +256,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
.unwrap_or(issued_span);
|
||||
|
||||
let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
|
||||
let tcx = self.tcx;
|
||||
|
||||
// FIXME: supply non-"" `opt_via` when appropriate
|
||||
let mut err = match (
|
||||
@ -265,7 +268,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
"mutable",
|
||||
) {
|
||||
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
|
||||
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
|
||||
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
|
||||
.cannot_reborrow_already_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
@ -279,7 +282,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => self.tcx
|
||||
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
|
||||
.cannot_mutably_borrow_multiply(
|
||||
span,
|
||||
&desc_place,
|
||||
@ -290,7 +293,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx
|
||||
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
|
||||
.cannot_uniquely_borrow_by_two_closures(
|
||||
span,
|
||||
&desc_place,
|
||||
@ -299,7 +302,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure(
|
||||
(BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
|
||||
span,
|
||||
&desc_place,
|
||||
"",
|
||||
@ -310,7 +313,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx
|
||||
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
|
||||
.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
@ -322,7 +325,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => self.tcx
|
||||
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
|
||||
.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
@ -466,7 +469,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
_proper_span: Span,
|
||||
end_span: Option<Span>,
|
||||
) {
|
||||
let mut err = self.tcx.path_does_not_live_long_enough(
|
||||
let tcx = self.tcx;
|
||||
let mut err = tcx.path_does_not_live_long_enough(
|
||||
borrow_span,
|
||||
&format!("`{}`", name),
|
||||
Origin::Mir,
|
||||
@ -493,9 +497,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
proper_span: Span,
|
||||
end_span: Option<Span>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let mut err =
|
||||
self.tcx
|
||||
.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
|
||||
tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
|
||||
err.span_label(proper_span, "temporary value does not live long enough");
|
||||
err.span_label(
|
||||
drop_span,
|
||||
@ -527,7 +531,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
context, name, scope_tree, borrow, drop_span, borrow_span
|
||||
);
|
||||
|
||||
let mut err = self.tcx.path_does_not_live_long_enough(
|
||||
let tcx = self.tcx;
|
||||
let mut err = tcx.path_does_not_live_long_enough(
|
||||
borrow_span,
|
||||
&format!("`{}`", name),
|
||||
Origin::Mir,
|
||||
@ -535,8 +540,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
err.span_label(drop_span, "borrowed value only lives until here");
|
||||
|
||||
if !self.tcx.nll() {
|
||||
self.tcx.note_and_explain_region(
|
||||
if !tcx.nll() {
|
||||
tcx.note_and_explain_region(
|
||||
scope_tree,
|
||||
&mut err,
|
||||
"borrowed value must be valid for ",
|
||||
@ -566,14 +571,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
context, scope_tree, borrow, drop_span, proper_span
|
||||
);
|
||||
|
||||
let tcx = self.tcx;
|
||||
let mut err =
|
||||
self.tcx
|
||||
.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
|
||||
tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
|
||||
err.span_label(proper_span, "temporary value does not live long enough");
|
||||
err.span_label(drop_span, "temporary value only lives until here");
|
||||
|
||||
if !self.tcx.nll() {
|
||||
self.tcx.note_and_explain_region(
|
||||
if !tcx.nll() {
|
||||
tcx.note_and_explain_region(
|
||||
scope_tree,
|
||||
&mut err,
|
||||
"borrowed value must be valid for ",
|
||||
@ -592,7 +597,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
(place, span): (&Place<'tcx>, Span),
|
||||
loan: &BorrowData<'tcx>,
|
||||
) {
|
||||
let mut err = self.tcx.cannot_assign_to_borrowed(
|
||||
let tcx = self.tcx;
|
||||
let mut err = tcx.cannot_assign_to_borrowed(
|
||||
span,
|
||||
self.retrieve_borrow_span(loan),
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
//! This query borrow-checks the MIR to (further) ensure it is not broken.
|
||||
|
||||
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::region_infer::{RegionInferenceContext, RegionCausalInfo};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map::definitions::DefPathData;
|
||||
@ -231,6 +231,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
access_place_error_reported: FxHashSet(),
|
||||
reservation_error_reported: FxHashSet(),
|
||||
nonlexical_regioncx: opt_regioncx.clone(),
|
||||
nonlexical_cause_info: None,
|
||||
};
|
||||
|
||||
let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id);
|
||||
@ -311,6 +312,7 @@ 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: Option<Rc<RegionInferenceContext<'tcx>>>,
|
||||
nonlexical_cause_info: Option<RegionCausalInfo>,
|
||||
}
|
||||
|
||||
// Check that:
|
||||
|
@ -18,16 +18,26 @@ use rustc_errors::DiagnosticBuilder;
|
||||
use util::liveness::{self, DefUse, LivenessMode};
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Adds annotations to `err` explaining *why* the borrow contains the
|
||||
/// point from `context`. This is key for the "3-point errors"
|
||||
/// [described in the NLL RFC][d].
|
||||
///
|
||||
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
|
||||
pub(in borrow_check) fn explain_why_borrow_contains_point(
|
||||
&self,
|
||||
&mut self,
|
||||
context: Context,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
if let Some(regioncx) = &self.nonlexical_regioncx {
|
||||
if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
|
||||
let mir = self.mir;
|
||||
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() {
|
||||
Cause::LiveVar(local, location) => {
|
||||
match find_regular_use(&mir, regioncx, borrow, location, local) {
|
||||
|
@ -72,6 +72,8 @@ pub struct RegionInferenceContext<'tcx> {
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
}
|
||||
|
||||
struct TrackCauses(bool);
|
||||
|
||||
struct RegionDefinition<'tcx> {
|
||||
/// Why we created this variable. Mostly these will be
|
||||
/// `RegionVariableOrigin::NLL`, but some variables get created
|
||||
@ -122,6 +124,10 @@ pub(crate) enum Cause {
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct RegionCausalInfo {
|
||||
inferred_values: RegionValues,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Constraint {
|
||||
// NB. The ordering here is not significant for correctness, but
|
||||
@ -343,17 +349,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
inferred_values.contains(r.to_region_vid(), p)
|
||||
}
|
||||
|
||||
/// Returns the *reason* that the region `r` contains the given point.
|
||||
pub(crate) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
|
||||
where
|
||||
R: ToRegionVid,
|
||||
{
|
||||
let inferred_values = self.inferred_values
|
||||
.as_ref()
|
||||
.expect("region values not yet inferred");
|
||||
inferred_values.cause(r.to_region_vid(), p)
|
||||
}
|
||||
|
||||
/// Returns access to the value of `r` for debugging purposes.
|
||||
pub(super) fn region_value_str(&self, r: RegionVid) -> String {
|
||||
let inferred_values = self.inferred_values
|
||||
@ -444,13 +439,25 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 inferred_values = self.compute_region_values(mir, 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>) {
|
||||
debug!("propagate_constraints()");
|
||||
debug!("propagate_constraints: constraints={:#?}", {
|
||||
let inferred_values = self.compute_region_values(mir, TrackCauses(false));
|
||||
self.inferred_values = Some(inferred_values);
|
||||
}
|
||||
|
||||
fn compute_region_values(&self, mir: &Mir<'tcx>, track_causes: TrackCauses) -> RegionValues {
|
||||
debug!("compute_region_values()");
|
||||
debug!("compute_region_values: constraints={:#?}", {
|
||||
let mut constraints: Vec<_> = self.constraints.iter().collect();
|
||||
constraints.sort();
|
||||
constraints
|
||||
@ -458,7 +465,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
// The initial values for each region are derived from the liveness
|
||||
// constraints we have accumulated.
|
||||
let mut inferred_values = self.liveness_constraints.clone();
|
||||
let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
|
||||
|
||||
let dependency_map = self.build_dependency_map();
|
||||
|
||||
@ -502,7 +509,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
debug!("\n");
|
||||
}
|
||||
|
||||
self.inferred_values = Some(inferred_values);
|
||||
inferred_values
|
||||
}
|
||||
|
||||
/// Builds up a map from each region variable X to a vector with the
|
||||
@ -1092,6 +1099,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -17,7 +17,7 @@ use rustc::mir::{BasicBlock, Location, Mir};
|
||||
use rustc::ty::RegionVid;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use super::{Cause, CauseExt};
|
||||
use super::{Cause, CauseExt, TrackCauses};
|
||||
|
||||
/// Maps between the various kinds of elements of a region value to
|
||||
/// the internal indices that w use.
|
||||
@ -184,7 +184,6 @@ impl ToElementIndex for RegionElementIndex {
|
||||
/// compact `SparseBitMatrix` representation, with one row per region
|
||||
/// variable. The columns consist of either universal regions or
|
||||
/// points in the CFG.
|
||||
#[derive(Clone)]
|
||||
pub(super) struct RegionValues {
|
||||
elements: Rc<RegionValueElements>,
|
||||
matrix: SparseBitMatrix<RegionVid, RegionElementIndex>,
|
||||
@ -199,6 +198,9 @@ pub(super) struct RegionValues {
|
||||
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
|
||||
|
||||
impl RegionValues {
|
||||
/// Creates a new set of "region values" that tracks causal information.
|
||||
/// Each of the regions in num_region_variables will be initialized with an
|
||||
/// empty set of points and no causal information.
|
||||
pub(super) fn new(
|
||||
elements: &Rc<RegionValueElements>,
|
||||
num_region_variables: usize,
|
||||
@ -218,6 +220,24 @@ impl RegionValues {
|
||||
}
|
||||
}
|
||||
|
||||
/// Duplicates the region values. If track_causes is false, then the
|
||||
/// resulting value will not track causal information (and any existing
|
||||
/// causal information is dropped). Otherwise, the causal information is
|
||||
/// preserved and maintained. Tracking the causal information makes region
|
||||
/// propagation significantly slower, so we prefer not to do it until an
|
||||
/// error is reported.
|
||||
pub(super) fn duplicate(&self, track_causes: TrackCauses) -> Self {
|
||||
Self {
|
||||
elements: self.elements.clone(),
|
||||
matrix: self.matrix.clone(),
|
||||
causes: if track_causes.0 {
|
||||
self.causes.clone()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the given element to the value for the given region. Returns true if
|
||||
/// the element is newly added (i.e., was not already present).
|
||||
pub(super) fn add<E: ToElementIndex>(&mut self, r: RegionVid, elem: E, cause: &Cause) -> bool {
|
||||
|
@ -78,6 +78,8 @@ LL | let cell = Cell::new(&a);
|
||||
...
|
||||
LL | }
|
||||
| - borrowed value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user