Skip to content

Commit 6ce46a8

Browse files
committed
record boring locals in polonius context
this is used in diagnostics to focus on relevant live locals to match NLL diagnostics
1 parent a8fc140 commit 6ce46a8

File tree

6 files changed

+69
-29
lines changed

6 files changed

+69
-29
lines changed

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,25 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
548548
}
549549
}
550550

551+
// NLL doesn't consider boring locals for liveness, and wouldn't encounter a
552+
// `Cause::LiveVar` for such a local. Polonius can't avoid computing liveness for boring
553+
// locals yet, and will encounter them when trying to explain why a borrow contains a given
554+
// point.
555+
//
556+
// We want to focus on relevant live locals in diagnostics, so when polonius is enabled, we
557+
// ensure that we don't emit live boring locals as explanations.
558+
let is_local_boring = |local| {
559+
if let Some(polonius_diagnostics) = self.polonius_diagnostics {
560+
polonius_diagnostics.boring_nll_locals.contains(&local)
561+
} else {
562+
assert!(!tcx.sess.opts.unstable_opts.polonius.is_next_enabled());
563+
564+
// Boring locals are never the cause of a borrow explanation in NLLs.
565+
false
566+
}
567+
};
551568
match find_use::find(body, regioncx, tcx, region_sub, use_location) {
552-
Some(Cause::LiveVar(local, location)) => {
569+
Some(Cause::LiveVar(local, location)) if !is_local_boring(local) => {
553570
let span = body.source_info(location).span;
554571
let spans = self
555572
.move_spans(Place::from(local).as_ref(), location)
@@ -592,7 +609,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
592609
}
593610
}
594611

595-
None => {
612+
Some(Cause::LiveVar(..)) | None => {
613+
// Here, under NLL: no cause was found. Under polonius: no cause was found, or a
614+
// boring local was found, which we ignore like NLLs do to match its diagnostics.
596615
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
597616
let (category, from_closure, span, region_name, path) =
598617
self.free_region_constraint_info(borrow_region_vid, region);

compiler/rustc_borrowck/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use crate::diagnostics::{
6060
use crate::path_utils::*;
6161
use crate::place_ext::PlaceExt;
6262
use crate::places_conflict::{PlaceConflictBias, places_conflict};
63+
use crate::polonius::PoloniusDiagnosticsContext;
6364
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
6465
use crate::prefixes::PrefixSet;
6566
use crate::region_infer::RegionInferenceContext;
@@ -270,6 +271,7 @@ fn do_mir_borrowck<'tcx>(
270271
polonius_output: None,
271272
move_errors: Vec::new(),
272273
diags_buffer,
274+
polonius_diagnostics: polonius_diagnostics.as_ref(),
273275
};
274276
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
275277
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
@@ -308,6 +310,7 @@ fn do_mir_borrowck<'tcx>(
308310
polonius_output,
309311
move_errors: Vec::new(),
310312
diags_buffer,
313+
polonius_diagnostics: polonius_diagnostics.as_ref(),
311314
};
312315

313316
// Compute and report region errors, if any.
@@ -329,7 +332,7 @@ fn do_mir_borrowck<'tcx>(
329332
body,
330333
&regioncx,
331334
&borrow_set,
332-
polonius_diagnostics,
335+
polonius_diagnostics.as_ref(),
333336
&opt_closure_req,
334337
);
335338

@@ -579,6 +582,9 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
579582

580583
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
581584
move_errors: Vec<MoveError<'tcx>>,
585+
586+
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
587+
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
582588
}
583589

584590
// Check that:

compiler/rustc_borrowck/src/nll.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
145145

146146
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
147147
// and use them to compute loan liveness.
148-
let polonius_diagnostics = polonius_context.as_ref().map(|polonius_context| {
148+
let polonius_diagnostics = polonius_context.map(|polonius_context| {
149149
polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
150150
});
151151

compiler/rustc_borrowck/src/polonius/dump.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
2525
body: &Body<'tcx>,
2626
regioncx: &RegionInferenceContext<'tcx>,
2727
borrow_set: &BorrowSet<'tcx>,
28-
polonius_diagnostics: Option<PoloniusDiagnosticsContext>,
28+
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
2929
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
3030
) {
3131
let tcx = infcx.tcx;
@@ -37,7 +37,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
3737
return;
3838
}
3939

40-
let polonius_diagnostics_context =
40+
let polonius_diagnostics =
4141
polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");
4242

4343
let _: io::Result<()> = try {
@@ -47,7 +47,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
4747
body,
4848
regioncx,
4949
borrow_set,
50-
polonius_diagnostics_context.localized_outlives_constraints,
50+
&polonius_diagnostics.localized_outlives_constraints,
5151
closure_region_requirements,
5252
&mut file,
5353
)?;
@@ -65,7 +65,7 @@ fn emit_polonius_dump<'tcx>(
6565
body: &Body<'tcx>,
6666
regioncx: &RegionInferenceContext<'tcx>,
6767
borrow_set: &BorrowSet<'tcx>,
68-
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
68+
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
6969
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
7070
out: &mut dyn io::Write,
7171
) -> io::Result<()> {

compiler/rustc_borrowck/src/polonius/mod.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ mod typeck_constraints;
5252

5353
use std::collections::BTreeMap;
5454

55+
use rustc_data_structures::fx::FxHashSet;
5556
use rustc_index::bit_set::SparseBitMatrix;
5657
use rustc_index::interval::SparseIntervalMatrix;
57-
use rustc_middle::mir::Body;
58+
use rustc_middle::mir::{Body, Local};
5859
use rustc_middle::ty::{RegionVid, TyCtxt};
5960
use rustc_mir_dataflow::points::PointIndex;
6061

@@ -75,24 +76,33 @@ pub(crate) struct PoloniusLivenessContext {
7576
/// The expected edge direction per live region: the kind of directed edge we'll create as
7677
/// liveness constraints depends on the variance of types with respect to each contained region.
7778
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
79+
80+
/// The regions that outlive free regions are used to distinguish relevant live locals from
81+
/// boring locals. A boring local is one whose type contains only such regions. Polonius
82+
/// currently has more boring locals than NLLs so we record the latter to use in errors and
83+
/// diagnostics, to focus on the locals we consider relevant and match NLL diagnostics.
84+
pub(crate) boring_nll_locals: FxHashSet<Local>,
7885
}
7986

8087
/// This struct holds the data needed to create the Polonius localized constraints. Its data is
8188
/// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
8289
pub(crate) struct PoloniusContext {
90+
/// The liveness data we recorded during MIR typeck.
91+
liveness_context: PoloniusLivenessContext,
92+
8393
/// The set of regions that are live at a given point in the CFG, used to create localized
8494
/// outlives constraints between regions that are live at connected points in the CFG.
8595
live_regions: SparseBitMatrix<PointIndex, RegionVid>,
86-
87-
/// The expected edge direction per live region: the kind of directed edge we'll create as
88-
/// liveness constraints depends on the variance of types with respect to each contained region.
89-
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
9096
}
9197

9298
/// This struct holds the data needed by the borrowck error computation and diagnostics. Its data is
9399
/// computed from the [PoloniusContext] when computing NLL regions.
94100
pub(crate) struct PoloniusDiagnosticsContext {
101+
/// The localized outlives constraints that were computed in the main analysis.
95102
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
103+
104+
/// The liveness data computed during MIR typeck: [PoloniusLivenessContext::boring_nll_locals].
105+
pub(crate) boring_nll_locals: FxHashSet<Local>,
96106
}
97107

98108
/// The direction a constraint can flow into. Used to create liveness constraints according to
@@ -127,10 +137,7 @@ impl PoloniusContext {
127137
}
128138
}
129139

130-
PoloniusContext {
131-
live_regions: live_regions_per_point,
132-
live_region_variances: liveness_context.live_region_variances,
133-
}
140+
PoloniusContext { live_regions: live_regions_per_point, liveness_context }
134141
}
135142

136143
/// Computes live loans using the set of loans model for `-Zpolonius=next`.
@@ -144,12 +151,15 @@ impl PoloniusContext {
144151
///
145152
/// The constraint data will be used to compute errors and diagnostics.
146153
pub(crate) fn compute_loan_liveness<'tcx>(
147-
&self,
154+
self,
148155
tcx: TyCtxt<'tcx>,
149156
regioncx: &mut RegionInferenceContext<'tcx>,
150157
body: &Body<'tcx>,
151158
borrow_set: &BorrowSet<'tcx>,
152159
) -> PoloniusDiagnosticsContext {
160+
let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
161+
self.liveness_context;
162+
153163
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
154164
convert_typeck_constraints(
155165
tcx,
@@ -164,7 +174,7 @@ impl PoloniusContext {
164174
body,
165175
regioncx.liveness_constraints(),
166176
&self.live_regions,
167-
&self.live_region_variances,
177+
&live_region_variances,
168178
regioncx.universal_regions(),
169179
&mut localized_outlives_constraints,
170180
);
@@ -181,6 +191,6 @@ impl PoloniusContext {
181191
);
182192
regioncx.record_live_loans(live_loans);
183193

184-
PoloniusDiagnosticsContext { localized_outlives_constraints }
194+
PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
185195
}
186196
}

compiler/rustc_borrowck/src/type_check/liveness/mod.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,24 @@ pub(super) fn generate<'a, 'tcx>(
3838
) {
3939
debug!("liveness::generate");
4040

41+
let mut free_regions = regions_that_outlive_free_regions(
42+
typeck.infcx.num_region_vars(),
43+
&typeck.universal_regions,
44+
&typeck.constraints.outlives_constraints,
45+
);
46+
4147
// NLLs can avoid computing some liveness data here because its constraints are
4248
// location-insensitive, but that doesn't work in polonius: locals whose type contains a region
4349
// that outlives a free region are not necessarily live everywhere in a flow-sensitive setting,
4450
// unlike NLLs.
45-
let free_regions = if !typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
46-
regions_that_outlive_free_regions(
47-
typeck.infcx.num_region_vars(),
48-
&typeck.universal_regions,
49-
&typeck.constraints.outlives_constraints,
50-
)
51-
} else {
52-
typeck.universal_regions.universal_regions_iter().collect()
53-
};
51+
// We do record these regions in the polonius context, since they're used to differentiate
52+
// relevant and boring locals, which is a key distinction used later in diagnostics.
53+
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
54+
let (_, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
55+
typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
56+
boring_locals.into_iter().collect();
57+
free_regions = typeck.universal_regions.universal_regions_iter().collect();
58+
}
5459
let (relevant_live_locals, boring_locals) =
5560
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
5661

0 commit comments

Comments
 (0)