Skip to content

Commit 6a5a487

Browse files
committed
convert type-check constraints into NLL constraints on the fly
We used to accumulate a vector of type-check constraints, but now we generate them as we go, and just store the NLL-style `OutlivesConstraint` and `TypeTest` information.
1 parent ba6a7f7 commit 6a5a487

File tree

7 files changed

+339
-266
lines changed

7 files changed

+339
-266
lines changed

src/librustc_data_structures/indexed_vec.rs

+5
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ impl<I: Idx, T> IndexVec<I, T> {
367367
IndexVec { raw: Vec::new(), _marker: PhantomData }
368368
}
369369

370+
#[inline]
371+
pub fn from_raw(raw: Vec<T>) -> Self {
372+
IndexVec { raw, _marker: PhantomData }
373+
}
374+
370375
#[inline]
371376
pub fn with_capacity(capacity: usize) -> Self {
372377
IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData }

src/librustc_mir/borrow_check/nll/constraint_generation.rs

+43-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use borrow_check::borrow_set::BorrowSet;
1212
use borrow_check::location::LocationTable;
1313
use borrow_check::nll::facts::AllFacts;
14+
use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
15+
use borrow_check::nll::ToRegionVid;
1416
use rustc::hir;
1517
use rustc::infer::InferCtxt;
1618
use rustc::mir::visit::TyContext;
@@ -21,9 +23,7 @@ use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator};
2123
use rustc::ty::fold::TypeFoldable;
2224
use rustc::ty::subst::Substs;
2325
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts};
24-
25-
use super::region_infer::{Cause, RegionInferenceContext};
26-
use super::ToRegionVid;
26+
use std::iter;
2727

2828
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
2929
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
@@ -32,6 +32,7 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
3232
location_table: &LocationTable,
3333
mir: &Mir<'tcx>,
3434
borrow_set: &BorrowSet<'tcx>,
35+
liveness_set_from_typeck: &[(ty::Region<'tcx>, Location, Cause)],
3536
) {
3637
let mut cg = ConstraintGeneration {
3738
borrow_set,
@@ -42,6 +43,8 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
4243
mir,
4344
};
4445

46+
cg.add_region_liveness_constraints_from_type_check(liveness_set_from_typeck);
47+
4548
for (bb, data) in mir.basic_blocks().iter_enumerated() {
4649
cg.visit_basic_block_data(bb, data);
4750
}
@@ -209,7 +212,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
209212
self.add_reborrow_constraint(location, region, borrowed_place);
210213
}
211214

212-
_ => { }
215+
_ => {}
213216
}
214217

215218
self.super_rvalue(rvalue, location);
@@ -225,6 +228,42 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
225228
}
226229

227230
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
231+
/// The MIR type checker generates region liveness constraints
232+
/// that we also have to respect.
233+
fn add_region_liveness_constraints_from_type_check(
234+
&mut self,
235+
liveness_set: &[(ty::Region<'tcx>, Location, Cause)],
236+
) {
237+
debug!(
238+
"add_region_liveness_constraints_from_type_check(liveness_set={} items)",
239+
liveness_set.len(),
240+
);
241+
242+
let ConstraintGeneration {
243+
regioncx,
244+
location_table,
245+
all_facts,
246+
..
247+
} = self;
248+
249+
for (region, location, cause) in liveness_set {
250+
debug!("generate: {:#?} is live at {:#?}", region, location);
251+
let region_vid = regioncx.to_region_vid(region);
252+
regioncx.add_live_point(region_vid, *location, &cause);
253+
}
254+
255+
if let Some(all_facts) = all_facts {
256+
all_facts
257+
.region_live_at
258+
.extend(liveness_set.into_iter().flat_map(|(region, location, _)| {
259+
let r = regioncx.to_region_vid(region);
260+
let p1 = location_table.start_index(*location);
261+
let p2 = location_table.mid_index(*location);
262+
iter::once((r, p1)).chain(iter::once((r, p2)))
263+
}));
264+
}
265+
}
266+
228267
/// Some variable with type `live_ty` is "regular live" at
229268
/// `location` -- i.e., it may be used later. This means that all
230269
/// regions appearing in the type `live_ty` must be live at

src/librustc_mir/borrow_check/nll/mod.rs

+28-20
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use borrow_check::borrow_set::BorrowSet;
1212
use borrow_check::location::{LocationIndex, LocationTable};
1313
use borrow_check::nll::facts::AllFactsExt;
14+
use borrow_check::nll::type_check::MirTypeckRegionConstraints;
1415
use dataflow::indexes::BorrowIndex;
1516
use dataflow::move_paths::MoveData;
1617
use dataflow::FlowAtLocation;
@@ -41,7 +42,6 @@ mod facts;
4142
mod invalidation;
4243
crate mod region_infer;
4344
mod renumber;
44-
mod subtype_constraint_generation;
4545
crate mod type_check;
4646
mod universal_regions;
4747

@@ -91,53 +91,61 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
9191
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
9292
Option<ClosureRegionRequirements<'gcx>>,
9393
) {
94+
let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts
95+
|| infcx.tcx.sess.opts.debugging_opts.polonius
96+
{
97+
Some(AllFacts::default())
98+
} else {
99+
None
100+
};
101+
94102
// Run the MIR type-checker.
95103
let liveness = &LivenessResults::compute(mir);
96-
let constraint_sets = &type_check::type_check(
104+
let constraint_sets = type_check::type_check(
97105
infcx,
98106
param_env,
99107
mir,
100108
def_id,
101109
&universal_regions,
110+
location_table,
102111
&liveness,
112+
&mut all_facts,
103113
flow_inits,
104114
move_data,
105115
);
106116

107-
let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts
108-
|| infcx.tcx.sess.opts.debugging_opts.polonius
109-
{
110-
Some(AllFacts::default())
111-
} else {
112-
None
113-
};
114-
115117
if let Some(all_facts) = &mut all_facts {
116118
all_facts
117119
.universal_region
118120
.extend(universal_regions.universal_regions());
119121
}
120122

121-
// Create the region inference context, taking ownership of the region inference
122-
// data that was contained in `infcx`.
123+
// Create the region inference context, taking ownership of the
124+
// region inference data that was contained in `infcx`, and the
125+
// base constraints generated by the type-check.
123126
let var_origins = infcx.take_region_var_origins();
124-
let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
125-
126-
// Generate various constraints.
127-
subtype_constraint_generation::generate(
128-
&mut regioncx,
129-
&mut all_facts,
130-
location_table,
127+
let MirTypeckRegionConstraints {
128+
liveness_set,
129+
outlives_constraints,
130+
type_tests,
131+
} = constraint_sets;
132+
let mut regioncx = RegionInferenceContext::new(
133+
var_origins,
134+
universal_regions,
131135
mir,
132-
constraint_sets,
136+
outlives_constraints,
137+
type_tests,
133138
);
139+
140+
// Generate various additional constraints.
134141
constraint_generation::generate_constraints(
135142
infcx,
136143
&mut regioncx,
137144
&mut all_facts,
138145
location_table,
139146
&mir,
140147
borrow_set,
148+
&liveness_set,
141149
);
142150
invalidation::generate_invalidates(
143151
infcx,

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

+32-21
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,14 @@ pub struct OutlivesConstraint {
123123
// it is for convenience. Before we dump the constraints in the
124124
// debugging logs, we sort them, and we'd like the "super region"
125125
// to be first, etc. (In particular, span should remain last.)
126-
127126
/// The region SUP must outlive SUB...
128-
sup: RegionVid,
127+
pub sup: RegionVid,
129128

130129
/// Region that must be outlived.
131-
sub: RegionVid,
130+
pub sub: RegionVid,
132131

133132
/// At this location.
134-
point: Location,
133+
pub point: Location,
135134

136135
/// Later on, we thread the constraints onto a linked list
137136
/// grouped by their `sub` field. So if you had:
@@ -141,10 +140,10 @@ pub struct OutlivesConstraint {
141140
/// 0 | `'a: 'b` | Some(2)
142141
/// 1 | `'b: 'c` | None
143142
/// 2 | `'c: 'b` | None
144-
next: Option<ConstraintIndex>,
143+
pub next: Option<ConstraintIndex>,
145144

146145
/// Where did this constraint arise?
147-
span: Span,
146+
pub span: Span,
148147
}
149148

150149
newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
@@ -240,11 +239,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
240239
/// `num_region_variables` valid inference variables; the first N
241240
/// of those will be constant regions representing the free
242241
/// regions defined in `universal_regions`.
242+
///
243+
/// The `outlives_constraints` and `type_tests` are an initial set
244+
/// of constraints produced by the MIR type check.
243245
pub(crate) fn new(
244246
var_infos: VarInfos,
245247
universal_regions: UniversalRegions<'tcx>,
246248
mir: &Mir<'tcx>,
249+
outlives_constraints: Vec<OutlivesConstraint>,
250+
type_tests: Vec<TypeTest<'tcx>>,
247251
) -> Self {
252+
// The `next` field should not yet have been initialized:
253+
debug_assert!(outlives_constraints.iter().all(|c| c.next.is_none()));
254+
248255
let num_region_variables = var_infos.len();
249256
let num_universal_regions = universal_regions.len();
250257

@@ -262,8 +269,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
262269
liveness_constraints: RegionValues::new(elements, num_region_variables),
263270
inferred_values: None,
264271
dependency_map: None,
265-
constraints: IndexVec::new(),
266-
type_tests: Vec::new(),
272+
constraints: IndexVec::from_raw(outlives_constraints),
273+
type_tests,
267274
universal_regions,
268275
};
269276

@@ -346,15 +353,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
346353
where
347354
R: ToRegionVid,
348355
{
349-
let inferred_values = self.inferred_values
356+
let inferred_values = self
357+
.inferred_values
350358
.as_ref()
351359
.expect("region values not yet inferred");
352360
inferred_values.contains(r.to_region_vid(), p)
353361
}
354362

355363
/// Returns access to the value of `r` for debugging purposes.
356364
crate fn region_value_str(&self, r: RegionVid) -> String {
357-
let inferred_values = self.inferred_values
365+
let inferred_values = self
366+
.inferred_values
358367
.as_ref()
359368
.expect("region values not yet inferred");
360369

@@ -397,11 +406,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
397406
});
398407
}
399408

400-
/// Add a "type test" that must be satisfied.
401-
pub(super) fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
402-
self.type_tests.push(type_test);
403-
}
404-
405409
/// Perform region inference and report errors if we see any
406410
/// unsatisfiable constraints. If this is a closure, returns the
407411
/// region requirements to propagate to our creator, if any.
@@ -596,7 +600,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
596600
if self.universal_regions.is_universal_region(r) {
597601
return self.definitions[r].external_name;
598602
} else {
599-
let inferred_values = self.inferred_values
603+
let inferred_values = self
604+
.inferred_values
600605
.as_ref()
601606
.expect("region values not yet inferred");
602607
let upper_bound = self.universal_upper_bound(r);
@@ -635,8 +640,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
635640
// region, which ensures it can be encoded in a `ClosureOutlivesRequirement`.
636641
let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound);
637642
assert!(self.universal_regions.is_universal_region(lower_bound_plus));
638-
assert!(!self.universal_regions
639-
.is_local_free_region(lower_bound_plus));
643+
assert!(
644+
!self
645+
.universal_regions
646+
.is_local_free_region(lower_bound_plus)
647+
);
640648

641649
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
642650
subject,
@@ -664,7 +672,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
664672
) -> Option<ClosureOutlivesSubject<'gcx>> {
665673
let tcx = infcx.tcx;
666674
let gcx = tcx.global_tcx();
667-
let inferred_values = self.inferred_values
675+
let inferred_values = self
676+
.inferred_values
668677
.as_ref()
669678
.expect("region values not yet inferred");
670679

@@ -845,7 +854,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
845854
sup_region, sub_region, point
846855
);
847856

848-
let inferred_values = self.inferred_values
857+
let inferred_values = self
858+
.inferred_values
849859
.as_ref()
850860
.expect("values for regions not yet inferred");
851861

@@ -912,7 +922,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
912922
) {
913923
// The universal regions are always found in a prefix of the
914924
// full list.
915-
let universal_definitions = self.definitions
925+
let universal_definitions = self
926+
.definitions
916927
.iter_enumerated()
917928
.take_while(|(_, fr_definition)| fr_definition.is_universal);
918929

0 commit comments

Comments
 (0)