Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NLL] Make causal tracking lazy #48682

Merged
merged 4 commits into from
Mar 9, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
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),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

_ => 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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but needs a comment:


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

&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
Original file line number Diff line number Diff line change
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
Loading