Skip to content

Commit

Permalink
Make causal tracking lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
spastorino committed Mar 6, 2018
1 parent ec76190 commit c85c5a0
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 43 deletions.
19 changes: 16 additions & 3 deletions src/librustc/infer/error_reporting/mod.rs
Expand Up @@ -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),

Expand Down Expand Up @@ -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;
Expand Down
44 changes: 25 additions & 19 deletions src/librustc_mir/borrow_check/error_reporting.rs
Expand Up @@ -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(),
Expand All @@ -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,
Expand All @@ -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),
Expand Down Expand Up @@ -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 (
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
"",
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -527,16 +531,17 @@ 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,
);
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 ",
Expand Down Expand Up @@ -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 ",
Expand All @@ -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()),
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
16 changes: 13 additions & 3 deletions src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
Expand Up @@ -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) {
Expand Down
47 changes: 32 additions & 15 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -444,21 +439,33 @@ 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
});

// 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();

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit c85c5a0

Please sign in to comment.