Skip to content

Commit 2f77039

Browse files
committed
set up skeleton for localized constraints conversion
1 parent 2b38a8b commit 2f77039

File tree

4 files changed

+164
-1
lines changed

4 files changed

+164
-1
lines changed

compiler/rustc_borrowck/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ fn do_mir_borrowck<'tcx>(
206206
polonius_output,
207207
opt_closure_req,
208208
nll_errors,
209+
localized_outlives_constraints,
209210
} = nll::compute_regions(
210211
&infcx,
211212
free_regions,

compiler/rustc_borrowck/src/nll.rs

+17
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::consumers::ConsumerOptions;
2929
use crate::diagnostics::RegionErrors;
3030
use crate::facts::{AllFacts, AllFactsExt, RustcFacts};
3131
use crate::location::LocationTable;
32+
use crate::polonius::LocalizedOutlivesConstraintSet;
3233
use crate::region_infer::RegionInferenceContext;
3334
use crate::type_check::{self, MirTypeckResults};
3435
use crate::universal_regions::UniversalRegions;
@@ -45,6 +46,9 @@ pub(crate) struct NllOutput<'tcx> {
4546
pub polonius_output: Option<Box<PoloniusOutput>>,
4647
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
4748
pub nll_errors: RegionErrors<'tcx>,
49+
50+
/// When using `-Zpolonius=next`: the localized typeck and liveness constraints.
51+
pub localized_outlives_constraints: LocalizedOutlivesConstraintSet,
4852
}
4953

5054
/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
@@ -135,6 +139,18 @@ pub(crate) fn compute_regions<'a, 'tcx>(
135139
elements,
136140
);
137141

142+
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
143+
// constraints.
144+
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
145+
if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
146+
polonius::create_localized_constraints(
147+
&mut regioncx,
148+
infcx.infcx.tcx,
149+
body,
150+
&mut localized_outlives_constraints,
151+
);
152+
}
153+
138154
// If requested: dump NLL facts, and run legacy polonius analysis.
139155
let polonius_output = all_facts.as_ref().and_then(|all_facts| {
140156
if infcx.tcx.sess.opts.unstable_opts.nll_facts {
@@ -175,6 +191,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
175191
polonius_output,
176192
opt_closure_req: closure_region_requirements,
177193
nll_errors,
194+
localized_outlives_constraints,
178195
}
179196
}
180197

compiler/rustc_borrowck/src/polonius/mod.rs

+142-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,146 @@
3535
3636
mod constraints;
3737
pub(crate) use constraints::*;
38-
3938
pub(crate) mod legacy;
39+
40+
use rustc_middle::mir::{Body, Location};
41+
use rustc_middle::ty::TyCtxt;
42+
use rustc_mir_dataflow::points::PointIndex;
43+
44+
use crate::RegionInferenceContext;
45+
use crate::constraints::OutlivesConstraint;
46+
use crate::region_infer::values::LivenessValues;
47+
use crate::type_check::Locations;
48+
use crate::universal_regions::UniversalRegions;
49+
50+
/// When using `-Zpolonius=next`, fills the given constraint set by:
51+
/// - converting NLL typeck constraints to be localized
52+
/// - encoding liveness constraints
53+
pub(crate) fn create_localized_constraints<'tcx>(
54+
regioncx: &mut RegionInferenceContext<'tcx>,
55+
tcx: TyCtxt<'tcx>,
56+
body: &Body<'tcx>,
57+
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
58+
) {
59+
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
60+
return;
61+
}
62+
63+
convert_typeck_constraints(
64+
body,
65+
regioncx.liveness_constraints(),
66+
regioncx.outlives_constraints(),
67+
localized_outlives_constraints,
68+
);
69+
create_liveness_constraints(
70+
body,
71+
regioncx.liveness_constraints(),
72+
regioncx.universal_regions(),
73+
localized_outlives_constraints,
74+
);
75+
76+
// FIXME: here, we can trace loan reachability in the constraint graph and record this as loan
77+
// liveness for the next step in the chain, the NLL loan scope and active loans computations.
78+
}
79+
80+
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the
81+
/// location where effects start to be visible).
82+
fn convert_typeck_constraints<'tcx>(
83+
body: &Body<'tcx>,
84+
liveness: &LivenessValues,
85+
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
86+
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
87+
) {
88+
for outlives_constraint in outlives_constraints {
89+
match outlives_constraint.locations {
90+
Locations::All(_) => {
91+
// FIXME: for now, turn logical constraints holding at all points into physical
92+
// edges at every point in the graph. We can encode this into *traversal* instead.
93+
for (block, bb) in body.basic_blocks.iter_enumerated() {
94+
let statement_count = bb.statements.len();
95+
for statement_index in 0..=statement_count {
96+
let current_location = Location { block, statement_index };
97+
let current_point = liveness.point_from_location(current_location);
98+
99+
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
100+
source: outlives_constraint.sup,
101+
from: current_point,
102+
target: outlives_constraint.sub,
103+
to: current_point,
104+
});
105+
}
106+
}
107+
}
108+
109+
_ => {}
110+
}
111+
}
112+
}
113+
114+
/// Propagate loans throughout the CFG: for each statement in the MIR, create localized outlives
115+
/// constraints for loans that are propagated to the next statements.
116+
pub(crate) fn create_liveness_constraints<'tcx>(
117+
body: &Body<'tcx>,
118+
liveness: &LivenessValues,
119+
universal_regions: &UniversalRegions<'tcx>,
120+
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
121+
) {
122+
for (block, bb) in body.basic_blocks.iter_enumerated() {
123+
let statement_count = bb.statements.len();
124+
for statement_index in 0..=statement_count {
125+
let current_location = Location { block, statement_index };
126+
let current_point = liveness.point_from_location(current_location);
127+
128+
if statement_index < statement_count {
129+
// Intra-block edges, straight line constraints from each point to its successor
130+
// within the same block.
131+
let next_location = Location { block, statement_index: statement_index + 1 };
132+
let next_point = liveness.point_from_location(next_location);
133+
propagate_loans_between_points(
134+
current_point,
135+
next_point,
136+
liveness,
137+
universal_regions,
138+
localized_outlives_constraints,
139+
);
140+
} else {
141+
// Inter-block edges, from the block's terminator to each successor block's entry
142+
// point.
143+
for successor_block in bb.terminator().successors() {
144+
let next_location = Location { block: successor_block, statement_index: 0 };
145+
let next_point = liveness.point_from_location(next_location);
146+
propagate_loans_between_points(
147+
current_point,
148+
next_point,
149+
liveness,
150+
universal_regions,
151+
localized_outlives_constraints,
152+
);
153+
}
154+
}
155+
}
156+
}
157+
}
158+
159+
/// Propagate loans within a region between two points in the CFG, if that region is live at both
160+
/// the source and target points.
161+
fn propagate_loans_between_points(
162+
current_point: PointIndex,
163+
next_point: PointIndex,
164+
_liveness: &LivenessValues,
165+
universal_regions: &UniversalRegions<'_>,
166+
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
167+
) {
168+
// Universal regions are semantically live at all points.
169+
// FIXME: We always have universal regions but they're not always (or often) involved in the
170+
// subset graph. So for now, we emit this edge, but we only need to emit edges for universal
171+
// regions that existential regions can actually reach.
172+
for region in universal_regions.universal_regions_iter() {
173+
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
174+
source: region,
175+
from: current_point,
176+
target: region,
177+
to: next_point,
178+
});
179+
}
180+
}

compiler/rustc_borrowck/src/region_infer/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2224,6 +2224,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22242224
fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
22252225
self.constraint_sccs.annotation(scc).representative
22262226
}
2227+
2228+
pub(crate) fn liveness_constraints(&self) -> &LivenessValues {
2229+
&self.liveness_constraints
2230+
}
22272231
}
22282232

22292233
impl<'tcx> RegionDefinition<'tcx> {

0 commit comments

Comments
 (0)