Skip to content

Commit 938c3d7

Browse files
committed
Make causal tracking lazy
1 parent ec76190 commit 938c3d7

File tree

5 files changed

+95
-40
lines changed

5 files changed

+95
-40
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
124124
(place, span): (&Place<'tcx>, Span),
125125
borrow: &BorrowData<'tcx>,
126126
) {
127+
let tcx = self.tcx;
127128
let value_msg = match self.describe_place(place) {
128129
Some(name) => format!("`{}`", name),
129130
None => "value".to_owned(),
@@ -132,7 +133,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
132133
Some(name) => format!("`{}`", name),
133134
None => "value".to_owned(),
134135
};
135-
let mut err = self.tcx.cannot_move_when_borrowed(
136+
let mut err = tcx.cannot_move_when_borrowed(
136137
span,
137138
&self.describe_place(place).unwrap_or("_".to_owned()),
138139
Origin::Mir,
@@ -152,7 +153,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
152153
(place, span): (&Place<'tcx>, Span),
153154
borrow: &BorrowData<'tcx>,
154155
) {
155-
let mut err = self.tcx.cannot_use_when_mutably_borrowed(
156+
let tcx = self.tcx;
157+
let mut err = tcx.cannot_use_when_mutably_borrowed(
156158
span,
157159
&self.describe_place(place).unwrap_or("_".to_owned()),
158160
self.retrieve_borrow_span(borrow),
@@ -254,6 +256,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
254256
.unwrap_or(issued_span);
255257

256258
let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
259+
let tcx = self.tcx;
257260

258261
// FIXME: supply non-"" `opt_via` when appropriate
259262
let mut err = match (
@@ -265,7 +268,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
265268
"mutable",
266269
) {
267270
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
268-
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
271+
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
269272
.cannot_reborrow_already_borrowed(
270273
span,
271274
&desc_place,
@@ -279,7 +282,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
279282
Origin::Mir,
280283
),
281284

282-
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => self.tcx
285+
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
283286
.cannot_mutably_borrow_multiply(
284287
span,
285288
&desc_place,
@@ -290,7 +293,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
290293
Origin::Mir,
291294
),
292295

293-
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx
296+
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
294297
.cannot_uniquely_borrow_by_two_closures(
295298
span,
296299
&desc_place,
@@ -299,7 +302,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
299302
Origin::Mir,
300303
),
301304

302-
(BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure(
305+
(BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
303306
span,
304307
&desc_place,
305308
"",
@@ -310,7 +313,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
310313
Origin::Mir,
311314
),
312315

313-
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx
316+
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
314317
.cannot_reborrow_already_uniquely_borrowed(
315318
span,
316319
&desc_place,
@@ -322,7 +325,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
322325
Origin::Mir,
323326
),
324327

325-
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => self.tcx
328+
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
326329
.cannot_reborrow_already_uniquely_borrowed(
327330
span,
328331
&desc_place,
@@ -466,7 +469,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
466469
_proper_span: Span,
467470
end_span: Option<Span>,
468471
) {
469-
let mut err = self.tcx.path_does_not_live_long_enough(
472+
let tcx = self.tcx;
473+
let mut err = tcx.path_does_not_live_long_enough(
470474
borrow_span,
471475
&format!("`{}`", name),
472476
Origin::Mir,
@@ -493,9 +497,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
493497
proper_span: Span,
494498
end_span: Option<Span>,
495499
) {
500+
let tcx = self.tcx;
496501
let mut err =
497-
self.tcx
498-
.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
502+
tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
499503
err.span_label(proper_span, "temporary value does not live long enough");
500504
err.span_label(
501505
drop_span,
@@ -527,16 +531,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
527531
context, name, scope_tree, borrow, drop_span, borrow_span
528532
);
529533

530-
let mut err = self.tcx.path_does_not_live_long_enough(
534+
let tcx = self.tcx;
535+
let mut err = tcx.path_does_not_live_long_enough(
531536
borrow_span,
532537
&format!("`{}`", name),
533538
Origin::Mir,
534539
);
535540
err.span_label(borrow_span, "borrowed value does not live long enough");
536541
err.span_label(drop_span, "borrowed value only lives until here");
537542

538-
if !self.tcx.nll() {
539-
self.tcx.note_and_explain_region(
543+
if !tcx.nll() {
544+
tcx.note_and_explain_region(
540545
scope_tree,
541546
&mut err,
542547
"borrowed value must be valid for ",
@@ -566,14 +571,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
566571
context, scope_tree, borrow, drop_span, proper_span
567572
);
568573

574+
let tcx = self.tcx;
569575
let mut err =
570-
self.tcx
571-
.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
576+
tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
572577
err.span_label(proper_span, "temporary value does not live long enough");
573578
err.span_label(drop_span, "temporary value only lives until here");
574579

575-
if !self.tcx.nll() {
576-
self.tcx.note_and_explain_region(
580+
if !tcx.nll() {
581+
tcx.note_and_explain_region(
577582
scope_tree,
578583
&mut err,
579584
"borrowed value must be valid for ",
@@ -592,7 +597,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
592597
(place, span): (&Place<'tcx>, Span),
593598
loan: &BorrowData<'tcx>,
594599
) {
595-
let mut err = self.tcx.cannot_assign_to_borrowed(
600+
let tcx = self.tcx;
601+
let mut err = tcx.cannot_assign_to_borrowed(
596602
span,
597603
self.retrieve_borrow_span(loan),
598604
&self.describe_place(place).unwrap_or("_".to_owned()),

src/librustc_mir/borrow_check/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//! This query borrow-checks the MIR to (further) ensure it is not broken.
1212
13-
use borrow_check::nll::region_infer::RegionInferenceContext;
13+
use borrow_check::nll::region_infer::{RegionInferenceContext, RegionCausalInfo};
1414
use rustc::hir;
1515
use rustc::hir::def_id::DefId;
1616
use rustc::hir::map::definitions::DefPathData;
@@ -231,6 +231,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
231231
access_place_error_reported: FxHashSet(),
232232
reservation_error_reported: FxHashSet(),
233233
nonlexical_regioncx: opt_regioncx.clone(),
234+
nonlexical_cause_info: None,
234235
};
235236

236237
let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id);
@@ -311,6 +312,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
311312
/// contains the results from region inference and lets us e.g.
312313
/// find out which CFG points are contained in each borrow region.
313314
nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
315+
nonlexical_cause_info: Option<RegionCausalInfo>,
314316
}
315317

316318
// Check that:

src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,26 @@ use rustc_errors::DiagnosticBuilder;
1818
use util::liveness::{self, DefUse, LivenessMode};
1919

2020
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
21+
/// Adds annotations to `err` explaining *why* the borrow contains the
22+
/// point from `context`. This is key for the "3-point errors"
23+
/// [described in the NLL RFC][d].
24+
///
25+
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
2126
pub(in borrow_check) fn explain_why_borrow_contains_point(
22-
&self,
27+
&mut self,
2328
context: Context,
2429
borrow: &BorrowData<'tcx>,
2530
err: &mut DiagnosticBuilder<'_>,
2631
) {
2732
if let Some(regioncx) = &self.nonlexical_regioncx {
28-
if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
29-
let mir = self.mir;
33+
let mir = self.mir;
3034

35+
if self.nonlexical_cause_info.is_none() {
36+
self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
37+
}
38+
39+
let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
40+
if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
3141
match *cause.root_cause() {
3242
Cause::LiveVar(local, location) => {
3343
match find_regular_use(&mir, regioncx, borrow, location, local) {

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub struct RegionInferenceContext<'tcx> {
7272
universal_regions: UniversalRegions<'tcx>,
7373
}
7474

75+
struct TrackCauses(bool);
76+
7577
struct RegionDefinition<'tcx> {
7678
/// Why we created this variable. Mostly these will be
7779
/// `RegionVariableOrigin::NLL`, but some variables get created
@@ -122,6 +124,10 @@ pub(crate) enum Cause {
122124
},
123125
}
124126

127+
pub(crate) struct RegionCausalInfo {
128+
inferred_values: RegionValues,
129+
}
130+
125131
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
126132
pub struct Constraint {
127133
// NB. The ordering here is not significant for correctness, but
@@ -343,17 +349,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
343349
inferred_values.contains(r.to_region_vid(), p)
344350
}
345351

346-
/// Returns the *reason* that the region `r` contains the given point.
347-
pub(crate) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
348-
where
349-
R: ToRegionVid,
350-
{
351-
let inferred_values = self.inferred_values
352-
.as_ref()
353-
.expect("region values not yet inferred");
354-
inferred_values.cause(r.to_region_vid(), p)
355-
}
356-
357352
/// Returns access to the value of `r` for debugging purposes.
358353
pub(super) fn region_value_str(&self, r: RegionVid) -> String {
359354
let inferred_values = self.inferred_values
@@ -444,21 +439,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
444439
}
445440
}
446441

442+
/// Re-execute the region inference, this time tracking causal information.
443+
/// This is significantly slower, so it is done only when an error is being reported.
444+
pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
445+
let inferred_values = self.compute_region_values(mir, TrackCauses(true));
446+
RegionCausalInfo { inferred_values }
447+
}
448+
447449
/// Propagate the region constraints: this will grow the values
448450
/// for each region variable until all the constraints are
449451
/// satisfied. Note that some values may grow **too** large to be
450452
/// feasible, but we check this later.
451453
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
452-
debug!("propagate_constraints()");
453-
debug!("propagate_constraints: constraints={:#?}", {
454+
let inferred_values = self.compute_region_values(mir, TrackCauses(false));
455+
self.inferred_values = Some(inferred_values);
456+
}
457+
458+
fn compute_region_values(&self, mir: &Mir<'tcx>, track_causes: TrackCauses) -> RegionValues {
459+
debug!("compute_region_values()");
460+
debug!("compute_region_values: constraints={:#?}", {
454461
let mut constraints: Vec<_> = self.constraints.iter().collect();
455462
constraints.sort();
456463
constraints
457464
});
458465

459466
// The initial values for each region are derived from the liveness
460467
// constraints we have accumulated.
461-
let mut inferred_values = self.liveness_constraints.clone();
468+
let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
462469

463470
let dependency_map = self.build_dependency_map();
464471

@@ -502,7 +509,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
502509
debug!("\n");
503510
}
504511

505-
self.inferred_values = Some(inferred_values);
512+
inferred_values
506513
}
507514

508515
/// Builds up a map from each region variable X to a vector with the
@@ -1092,6 +1099,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10921099
}
10931100
}
10941101

1102+
impl RegionCausalInfo {
1103+
/// Returns the *reason* that the region `r` contains the given point.
1104+
pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
1105+
where
1106+
R: ToRegionVid,
1107+
{
1108+
self.inferred_values.cause(r.to_region_vid(), p)
1109+
}
1110+
}
1111+
10951112
impl<'tcx> RegionDefinition<'tcx> {
10961113
fn new(origin: RegionVariableOrigin) -> Self {
10971114
// Create a new region definition. Note that, for free

src/librustc_mir/borrow_check/nll/region_infer/values.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc::mir::{BasicBlock, Location, Mir};
1717
use rustc::ty::RegionVid;
1818
use syntax::codemap::Span;
1919

20-
use super::{Cause, CauseExt};
20+
use super::{Cause, CauseExt, TrackCauses};
2121

2222
/// Maps between the various kinds of elements of a region value to
2323
/// the internal indices that w use.
@@ -184,7 +184,6 @@ impl ToElementIndex for RegionElementIndex {
184184
/// compact `SparseBitMatrix` representation, with one row per region
185185
/// variable. The columns consist of either universal regions or
186186
/// points in the CFG.
187-
#[derive(Clone)]
188187
pub(super) struct RegionValues {
189188
elements: Rc<RegionValueElements>,
190189
matrix: SparseBitMatrix<RegionVid, RegionElementIndex>,
@@ -199,6 +198,9 @@ pub(super) struct RegionValues {
199198
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
200199

201200
impl RegionValues {
201+
/// Creates a new set of "region values" that tracks causal information.
202+
/// Each of the regions in num_region_variables will be initialized with an
203+
/// empty set of points and no causal information.
202204
pub(super) fn new(
203205
elements: &Rc<RegionValueElements>,
204206
num_region_variables: usize,
@@ -218,6 +220,24 @@ impl RegionValues {
218220
}
219221
}
220222

223+
/// Duplicates the region values. If track_causes is false, then the
224+
/// resulting value will not track causal information (and any existing
225+
/// causal information is dropped). Otherwise, the causal information is
226+
/// preserved and maintained. Tracking the causal information makes region
227+
/// propagation significantly slower, so we prefer not to do it until an
228+
/// error is reported.
229+
pub(super) fn duplicate(&self, track_causes: TrackCauses) -> Self {
230+
Self {
231+
elements: self.elements.clone(),
232+
matrix: self.matrix.clone(),
233+
causes: if track_causes.0 {
234+
self.causes.clone()
235+
} else {
236+
None
237+
},
238+
}
239+
}
240+
221241
/// Adds the given element to the value for the given region. Returns true if
222242
/// the element is newly added (i.e., was not already present).
223243
pub(super) fn add<E: ToElementIndex>(&mut self, r: RegionVid, elem: E, cause: &Cause) -> bool {

0 commit comments

Comments
 (0)