Skip to content

Commit f03e067

Browse files
committed
Auto merge of #46582 - nikomatsakis:nll-master-to-rust-master-4, r=arielb1
make MIR type checker handle a number of other cases The existing type checker was primarily used to verify types, but was skipping over a number of details. For example, it was not checking that the predicates on functions were satisfied and so forth. This meant that the NLL region checker was not getting a lot of the constraints it needed. This PR closes those gaps. It also includes a bit of refactoring for the way that we store region values, encapsulating the bit matrix over into its own module and improving the data structures in use. This is mostly work by @spastorino being ported over from nll-master. r? @arielb1 or @pnkfelix
2 parents 0142781 + 237dd41 commit f03e067

29 files changed

+1093
-257
lines changed

src/librustc/infer/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
12011201
/// translate them into the form that the NLL solver
12021202
/// understands. See the NLL module for mode details.
12031203
pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
1204+
assert!(self.region_obligations.borrow().is_empty(),
1205+
"region_obligations not empty: {:#?}",
1206+
self.region_obligations.borrow());
1207+
12041208
self.borrow_region_constraints().take_and_reset_data()
12051209
}
12061210

src/librustc/infer/outlives/obligations.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
8888
body_id: ast::NodeId,
8989
obligation: RegionObligation<'tcx>,
9090
) {
91-
debug!("register_region_obligation({:?}, {:?})", body_id, obligation);
91+
debug!(
92+
"register_region_obligation(body_id={:?}, obligation={:?})",
93+
body_id,
94+
obligation
95+
);
96+
9297
self.region_obligations
9398
.borrow_mut()
9499
.push((body_id, obligation));
@@ -139,6 +144,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
139144
"cannot process registered region obligations in a snapshot"
140145
);
141146

147+
debug!("process_registered_region_obligations()");
148+
142149
// pull out the region obligations with the given `body_id` (leaving the rest)
143150
let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len());
144151
{
@@ -157,6 +164,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
157164
cause,
158165
} in my_region_obligations
159166
{
167+
debug!(
168+
"process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}",
169+
sup_type,
170+
sub_region,
171+
cause
172+
);
173+
160174
let origin = SubregionOrigin::from_obligation_cause(
161175
&cause,
162176
|| infer::RelateParamBound(cause.span, sup_type),

src/librustc/ty/context.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,9 @@ slice_interners!(
17081708
);
17091709

17101710
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
1711-
/// Create an unsafe fn ty based on a safe fn ty.
1711+
/// Given a `fn` type, returns an equivalent `unsafe fn` type;
1712+
/// that is, a `fn` type that is equivalent in every way for being
1713+
/// unsafe.
17121714
pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
17131715
assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
17141716
self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig {
@@ -1717,6 +1719,30 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
17171719
}))
17181720
}
17191721

1722+
/// Given a closure signature `sig`, returns an equivalent `fn`
1723+
/// type with the same signature. Detuples and so forth -- so
1724+
/// e.g. if we have a sig with `Fn<(u32, i32)>` then you would get
1725+
/// a `fn(u32, i32)`.
1726+
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
1727+
let converted_sig = sig.map_bound(|s| {
1728+
let params_iter = match s.inputs()[0].sty {
1729+
ty::TyTuple(params, _) => {
1730+
params.into_iter().cloned()
1731+
}
1732+
_ => bug!(),
1733+
};
1734+
self.mk_fn_sig(
1735+
params_iter,
1736+
s.output(),
1737+
s.variadic,
1738+
hir::Unsafety::Normal,
1739+
abi::Abi::Rust,
1740+
)
1741+
});
1742+
1743+
self.mk_fn_ptr(converted_sig)
1744+
}
1745+
17201746
// Interns a type/name combination, stores the resulting box in cx.interners,
17211747
// and returns the box as cast to an unsafe ptr (see comments for Ty above).
17221748
pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
7070
with_msg: &mut FnMut(&str) -> io::Result<()>,
7171
) -> io::Result<()> {
7272
for region in self.definitions.indices() {
73-
let value = self.region_value_str_from_matrix(&self.liveness_constraints, region);
73+
let value = self.liveness_constraints.region_value_str(region);
7474
if value != "{}" {
7575
with_msg(&format!("{:?} live at {}", region, value))?;
7676
}

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

+38-111
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location
1919
use rustc::ty::{self, RegionVid};
2020
use rustc_data_structures::indexed_vec::IndexVec;
2121
use rustc_data_structures::fx::FxHashSet;
22-
use rustc_data_structures::bitvec::BitMatrix;
23-
use rustc_data_structures::indexed_vec::Idx;
24-
use std::collections::BTreeMap;
2522
use std::fmt;
23+
use std::rc::Rc;
2624
use syntax_pos::Span;
2725

2826
mod annotation;
2927
mod dump_mir;
3028
mod graphviz;
29+
mod values;
30+
use self::values::{RegionValueElements, RegionValues};
3131

3232
pub struct RegionInferenceContext<'tcx> {
3333
/// Contains the definition for every region variable. Region
@@ -36,27 +36,22 @@ pub struct RegionInferenceContext<'tcx> {
3636
/// from as well as its final inferred value.
3737
definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
3838

39+
/// Maps from points/universal-regions to a `RegionElementIndex`.
40+
elements: Rc<RegionValueElements>,
41+
3942
/// The liveness constraints added to each region. For most
4043
/// regions, these start out empty and steadily grow, though for
4144
/// each universally quantified region R they start out containing
4245
/// the entire CFG and `end(R)`.
43-
///
44-
/// In this `BitMatrix` representation, the rows are the region
45-
/// variables and the columns are the free regions and MIR locations.
46-
liveness_constraints: BitMatrix,
46+
liveness_constraints: RegionValues,
4747

4848
/// The final inferred values of the inference variables; `None`
4949
/// until `solve` is invoked.
50-
inferred_values: Option<BitMatrix>,
50+
inferred_values: Option<RegionValues>,
5151

5252
/// The constraints we have accumulated and used during solving.
5353
constraints: Vec<Constraint>,
5454

55-
/// A map from each MIR Location to its column index in
56-
/// `liveness_constraints`/`inferred_values`. (The first N columns are
57-
/// the free regions.)
58-
point_indices: BTreeMap<Location, usize>,
59-
6055
/// Information about the universally quantified regions in scope
6156
/// on this function and their (known) relations to one another.
6257
universal_regions: UniversalRegions<'tcx>,
@@ -112,19 +107,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
112107
let num_region_variables = var_origins.len();
113108
let num_universal_regions = universal_regions.len();
114109

115-
let mut num_points = 0;
116-
let mut point_indices = BTreeMap::new();
117-
118-
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
119-
for statement_index in 0..block_data.statements.len() + 1 {
120-
let location = Location {
121-
block,
122-
statement_index,
123-
};
124-
point_indices.insert(location, num_universal_regions + num_points);
125-
num_points += 1;
126-
}
127-
}
110+
let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions));
128111

129112
// Create a RegionDefinition for each inference variable.
130113
let definitions = var_origins
@@ -134,13 +117,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
134117

135118
let mut result = Self {
136119
definitions,
137-
liveness_constraints: BitMatrix::new(
138-
num_region_variables,
139-
num_universal_regions + num_points,
140-
),
120+
elements: elements.clone(),
121+
liveness_constraints: RegionValues::new(elements, num_region_variables),
141122
inferred_values: None,
142123
constraints: Vec::new(),
143-
point_indices,
144124
universal_regions,
145125
};
146126

@@ -186,14 +166,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
186166
self.definitions[variable].is_universal = true;
187167

188168
// Add all nodes in the CFG to liveness constraints
189-
for (_location, point_index) in &self.point_indices {
190-
self.liveness_constraints
191-
.add(variable.index(), *point_index);
169+
for point_index in self.elements.all_point_indices() {
170+
self.liveness_constraints.add(variable, point_index);
192171
}
193172

194173
// Add `end(X)` into the set for X.
195-
self.liveness_constraints
196-
.add(variable.index(), variable.index());
174+
self.liveness_constraints.add(variable, variable);
197175
}
198176
}
199177

@@ -217,32 +195,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
217195
let inferred_values = self.inferred_values
218196
.as_ref()
219197
.expect("region values not yet inferred");
220-
self.region_contains_point_in_matrix(inferred_values, r, p)
221-
}
222-
223-
/// True if given region `r` contains the point `p`, when
224-
/// evaluated in the set of region values `matrix`.
225-
fn region_contains_point_in_matrix(
226-
&self,
227-
matrix: &BitMatrix,
228-
r: RegionVid,
229-
p: Location,
230-
) -> bool {
231-
let point_index = self.point_indices
232-
.get(&p)
233-
.expect("point index should be known");
234-
matrix.contains(r.index(), *point_index)
235-
}
236-
237-
/// True if given region `r` contains the `end(s)`, when
238-
/// evaluated in the set of region values `matrix`.
239-
fn region_contains_region_in_matrix(
240-
&self,
241-
matrix: &BitMatrix,
242-
r: RegionVid,
243-
s: RegionVid,
244-
) -> bool {
245-
matrix.contains(r.index(), s.index())
198+
inferred_values.contains(r, p)
246199
}
247200

248201
/// Returns access to the value of `r` for debugging purposes.
@@ -251,43 +204,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
251204
.as_ref()
252205
.expect("region values not yet inferred");
253206

254-
self.region_value_str_from_matrix(inferred_values, r)
255-
}
256-
257-
fn region_value_str_from_matrix(&self,
258-
matrix: &BitMatrix,
259-
r: RegionVid) -> String {
260-
let mut result = String::new();
261-
result.push_str("{");
262-
let mut sep = "";
263-
264-
for &point in self.point_indices.keys() {
265-
if self.region_contains_point_in_matrix(matrix, r, point) {
266-
result.push_str(&format!("{}{:?}", sep, point));
267-
sep = ", ";
268-
}
269-
}
270-
271-
for fr in (0..self.universal_regions.len()).map(RegionVid::new) {
272-
if self.region_contains_region_in_matrix(matrix, r, fr) {
273-
result.push_str(&format!("{}{:?}", sep, fr));
274-
sep = ", ";
275-
}
276-
}
277-
278-
result.push_str("}");
279-
280-
result
207+
inferred_values.region_value_str(r)
281208
}
282209

283210
/// Indicates that the region variable `v` is live at the point `point`.
211+
///
212+
/// Returns `true` if this constraint is new and `false` is the
213+
/// constraint was already present.
284214
pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) -> bool {
285215
debug!("add_live_point({:?}, {:?})", v, point);
286216
assert!(self.inferred_values.is_none(), "values already inferred");
287-
let point_index = self.point_indices
288-
.get(&point)
289-
.expect("point index should be known");
290-
self.liveness_constraints.add(v.index(), *point_index)
217+
debug!("add_live_point: @{:?}", point);
218+
219+
let element = self.elements.index(point);
220+
if self.liveness_constraints.add(v, element) {
221+
true
222+
} else {
223+
false
224+
}
291225
}
292226

293227
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
@@ -386,16 +320,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
386320
outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
387321
) {
388322
let inferred_values = self.inferred_values.as_ref().unwrap();
389-
let longer_value = inferred_values.iter(longer_fr.index());
390323

391324
debug!("check_universal_region(fr={:?})", longer_fr);
392325

393326
// Find every region `o` such that `fr: o`
394327
// (because `fr` includes `end(o)`).
395-
let shorter_frs = longer_value
396-
.take_while(|&i| i < self.universal_regions.len())
397-
.map(RegionVid::new);
398-
for shorter_fr in shorter_frs {
328+
for shorter_fr in inferred_values.universal_regions_outlived_by(longer_fr) {
399329
// If it is known that `fr: o`, carry on.
400330
if self.universal_regions.outlives(longer_fr, shorter_fr) {
401331
continue;
@@ -512,20 +442,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
512442

513443
fn copy(
514444
&self,
515-
inferred_values: &mut BitMatrix,
445+
inferred_values: &mut RegionValues,
516446
mir: &Mir<'tcx>,
517447
from_region: RegionVid,
518448
to_region: RegionVid,
519-
start_point: Location,
449+
constraint_point: Location,
520450
) -> bool {
521451
let mut changed = false;
522452

523453
let mut stack = vec![];
524454
let mut visited = FxHashSet();
525455

526-
stack.push(start_point);
456+
stack.push(constraint_point);
527457
while let Some(p) = stack.pop() {
528-
if !self.region_contains_point_in_matrix(inferred_values, from_region, p) {
458+
let point_index = self.elements.index(p);
459+
460+
if !inferred_values.contains(from_region, point_index) {
529461
debug!(" not in from-region");
530462
continue;
531463
}
@@ -535,8 +467,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
535467
continue;
536468
}
537469

538-
let point_index = self.point_indices.get(&p).unwrap();
539-
changed |= inferred_values.add(to_region.index(), *point_index);
470+
let new = inferred_values.add(to_region, point_index);
471+
changed |= new;
540472

541473
let block_data = &mir[p.block];
542474
let successor_points = if p.statement_index < block_data.statements.len() {
@@ -564,13 +496,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
564496
// If we reach the END point in the graph, then copy
565497
// over any skolemized end points in the `from_region`
566498
// and make sure they are included in the `to_region`.
567-
let universal_region_indices = inferred_values
568-
.iter(from_region.index())
569-
.take_while(|&i| i < self.universal_regions.len())
570-
.collect::<Vec<_>>();
571-
for fr in &universal_region_indices {
572-
changed |= inferred_values.add(to_region.index(), *fr);
573-
}
499+
changed |=
500+
inferred_values.add_universal_regions_outlived_by(from_region, to_region);
574501
} else {
575502
stack.extend(successor_points);
576503
}

0 commit comments

Comments
 (0)