Skip to content

Commit d1e67fc

Browse files
nikomatsakispnkfelix
authored andcommitted
remove universal-region-relation computation from universal_regions
1 parent 3bca170 commit d1e67fc

File tree

7 files changed

+206
-300
lines changed

7 files changed

+206
-300
lines changed

src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
111111
// Run the MIR type-checker.
112112
let liveness_map = NllLivenessMap::compute(&mir);
113113
let liveness = LivenessResults::compute(mir, &liveness_map);
114-
let constraint_sets = type_check::type_check(
114+
let (constraint_sets, universal_region_relations) = type_check::type_check(
115115
infcx,
116116
param_env,
117117
mir,
@@ -155,6 +155,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
155155
let mut regioncx = RegionInferenceContext::new(
156156
var_origins,
157157
universal_regions,
158+
universal_region_relations,
158159
mir,
159160
outlives_constraints,
160161
type_tests,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
3333
.universal_regions
3434
.region_classification(region)
3535
.unwrap();
36-
let outlived_by = self.universal_regions.regions_outlived_by(region);
36+
let outlived_by = self.universal_region_relations.regions_outlived_by(region);
3737
writeln!(
3838
out,
3939
"| {r:rw$} | {c:cw$} | {ob}",

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use borrow_check::nll::constraints::{
1515
};
1616
use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
1717
use borrow_check::nll::type_check::Locations;
18+
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
1819
use rustc::hir::def_id::DefId;
1920
use rustc::infer::canonical::QueryRegionConstraint;
2021
use rustc::infer::region_constraints::{GenericKind, VarInfos};
@@ -80,8 +81,12 @@ pub struct RegionInferenceContext<'tcx> {
8081
type_tests: Vec<TypeTest<'tcx>>,
8182

8283
/// Information about the universally quantified regions in scope
83-
/// on this function and their (known) relations to one another.
84+
/// on this function.
8485
universal_regions: Rc<UniversalRegions<'tcx>>,
86+
87+
/// Information about how the universally quantified regions in
88+
/// scope on this function relate to one another.
89+
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
8590
}
8691

8792
struct RegionDefinition<'tcx> {
@@ -207,6 +212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
207212
pub(crate) fn new(
208213
var_infos: VarInfos,
209214
universal_regions: Rc<UniversalRegions<'tcx>>,
215+
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
210216
_mir: &Mir<'tcx>,
211217
outlives_constraints: ConstraintSet,
212218
type_tests: Vec<TypeTest<'tcx>>,
@@ -249,6 +255,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
249255
scc_values,
250256
type_tests,
251257
universal_regions,
258+
universal_region_relations,
252259
};
253260

254261
result.init_free_and_bound_regions();
@@ -766,7 +773,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
766773

767774
// Grow further to get smallest universal region known to
768775
// creator.
769-
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
776+
let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
770777

771778
debug!(
772779
"non_local_universal_upper_bound: non_local_lub={:?}",
@@ -802,7 +809,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
802809
let mut lub = self.universal_regions.fr_fn_body;
803810
let r_scc = self.constraint_sccs.scc(r);
804811
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
805-
lub = self.universal_regions.postdom_upper_bound(lub, ur);
812+
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
806813
}
807814

808815
debug!("universal_upper_bound: r={:?} lub={:?}", r, lub);
@@ -870,7 +877,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
870877
.all(|r1| {
871878
self.scc_values
872879
.universal_regions_outlived_by(sup_region_scc)
873-
.any(|r2| self.universal_regions.outlives(r2, r1))
880+
.any(|r2| self.universal_region_relations.outlives(r2, r1))
874881
});
875882

876883
if !universal_outlives {
@@ -975,7 +982,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
975982
// (because `fr` includes `end(o)`).
976983
for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) {
977984
// If it is known that `fr: o`, carry on.
978-
if self.universal_regions.outlives(longer_fr, shorter_fr) {
985+
if self.universal_region_relations.outlives(longer_fr, shorter_fr) {
979986
continue;
980987
}
981988

@@ -989,14 +996,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
989996
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
990997
// Shrink `fr` until we find a non-local region (if we do).
991998
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
992-
if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
999+
if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) {
9931000
debug!("check_universal_region: fr_minus={:?}", fr_minus);
9941001

9951002
// Grow `shorter_fr` until we find a non-local
9961003
// region. (We always will.) We'll call that
9971004
// `shorter_fr+` -- it's ever so slightly larger than
9981005
// `fr`.
999-
let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
1006+
let shorter_fr_plus = self.universal_region_relations.non_local_upper_bound(shorter_fr);
10001007
debug!(
10011008
"check_universal_region: shorter_fr_plus={:?}",
10021009
shorter_fr_plus

src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
// except according to those terms.
1010

1111
use borrow_check::location::LocationTable;
12+
use borrow_check::nll::ToRegionVid;
1213
use borrow_check::nll::facts::AllFacts;
13-
use borrow_check::nll::universal_regions::UniversalRegions;
1414
use borrow_check::nll::type_check::constraint_conversion;
1515
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
16+
use borrow_check::nll::universal_regions::UniversalRegions;
1617
use rustc::hir::def_id::DefId;
18+
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
1719
use rustc::infer::region_constraints::GenericKind;
1820
use rustc::infer::InferCtxt;
1921
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
@@ -93,6 +95,107 @@ impl UniversalRegionRelations<'tcx> {
9395
self.outlives.add(fr_a, fr_b);
9496
self.inverse_outlives.add(fr_b, fr_a);
9597
}
98+
99+
/// Given two universal regions, returns the postdominating
100+
/// upper-bound (effectively the least upper bound).
101+
///
102+
/// (See `TransitiveRelation::postdom_upper_bound` for details on
103+
/// the postdominating upper bound in general.)
104+
crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
105+
assert!(self.universal_regions.is_universal_region(fr1));
106+
assert!(self.universal_regions.is_universal_region(fr2));
107+
*self
108+
.inverse_outlives
109+
.postdom_upper_bound(&fr1, &fr2)
110+
.unwrap_or(&self.universal_regions.fr_static)
111+
}
112+
113+
/// Finds an "upper bound" for `fr` that is not local. In other
114+
/// words, returns the smallest (*) known region `fr1` that (a)
115+
/// outlives `fr` and (b) is not local. This cannot fail, because
116+
/// we will always find `'static` at worst.
117+
///
118+
/// (*) If there are multiple competing choices, we pick the "postdominating"
119+
/// one. See `TransitiveRelation::postdom_upper_bound` for details.
120+
crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
121+
debug!("non_local_upper_bound(fr={:?})", fr);
122+
self.non_local_bound(&self.inverse_outlives, fr)
123+
.unwrap_or(self.universal_regions.fr_static)
124+
}
125+
126+
/// Finds a "lower bound" for `fr` that is not local. In other
127+
/// words, returns the largest (*) known region `fr1` that (a) is
128+
/// outlived by `fr` and (b) is not local. This cannot fail,
129+
/// because we will always find `'static` at worst.
130+
///
131+
/// (*) If there are multiple competing choices, we pick the "postdominating"
132+
/// one. See `TransitiveRelation::postdom_upper_bound` for details.
133+
crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
134+
debug!("non_local_lower_bound(fr={:?})", fr);
135+
self.non_local_bound(&self.outlives, fr)
136+
}
137+
138+
/// Helper for `non_local_upper_bound` and
139+
/// `non_local_lower_bound`. Repeatedly invokes `postdom_parent`
140+
/// until we find something that is not local. Returns None if we
141+
/// never do so.
142+
fn non_local_bound(
143+
&self,
144+
relation: &TransitiveRelation<RegionVid>,
145+
fr0: RegionVid,
146+
) -> Option<RegionVid> {
147+
// This method assumes that `fr0` is one of the universally
148+
// quantified region variables.
149+
assert!(self.universal_regions.is_universal_region(fr0));
150+
151+
let mut external_parents = vec![];
152+
let mut queue = vec![&fr0];
153+
154+
// Keep expanding `fr` into its parents until we reach
155+
// non-local regions.
156+
while let Some(fr) = queue.pop() {
157+
if !self.universal_regions.is_local_free_region(*fr) {
158+
external_parents.push(fr);
159+
continue;
160+
}
161+
162+
queue.extend(relation.parents(fr));
163+
}
164+
165+
debug!("non_local_bound: external_parents={:?}", external_parents);
166+
167+
// In case we find more than one, reduce to one for
168+
// convenience. This is to prevent us from generating more
169+
// complex constraints, but it will cause spurious errors.
170+
let post_dom = relation
171+
.mutual_immediate_postdominator(external_parents)
172+
.cloned();
173+
174+
debug!("non_local_bound: post_dom={:?}", post_dom);
175+
176+
post_dom.and_then(|post_dom| {
177+
// If the mutual immediate postdom is not local, then
178+
// there is no non-local result we can return.
179+
if !self.universal_regions.is_local_free_region(post_dom) {
180+
Some(post_dom)
181+
} else {
182+
None
183+
}
184+
})
185+
}
186+
187+
/// True if fr1 is known to outlive fr2.
188+
///
189+
/// This will only ever be true for universally quantified regions.
190+
crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
191+
self.outlives.contains(&fr1, &fr2)
192+
}
193+
194+
/// Returns a vector of free regions `x` such that `fr1: x` is
195+
/// known to hold.
196+
crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
197+
self.outlives.reachable_from(&fr1)
198+
}
96199
}
97200

98201
struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
@@ -223,3 +326,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
223326
}
224327
}
225328
}
329+
330+
/// This trait is used by the `impl-trait` constraint code to abstract
331+
/// over the `FreeRegionMap` from lexical regions and
332+
/// `UniversalRegions` (from NLL)`.
333+
impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
334+
fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool {
335+
let shorter = shorter.to_region_vid();
336+
assert!(self.universal_regions.is_universal_region(shorter));
337+
let longer = longer.to_region_vid();
338+
assert!(self.universal_regions.is_universal_region(longer));
339+
self.outlives(longer, shorter)
340+
}
341+
}

src/librustc_mir/borrow_check/nll/type_check/input_output.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//! contain revealed `impl Trait` values).
1919
2020
use borrow_check::nll::renumber;
21+
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
2122
use borrow_check::nll::universal_regions::UniversalRegions;
2223
use rustc::hir::def_id::DefId;
2324
use rustc::infer::InferOk;
@@ -37,6 +38,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
3738
mir: &Mir<'tcx>,
3839
mir_def_id: DefId,
3940
universal_regions: &UniversalRegions<'tcx>,
41+
universal_region_relations: &UniversalRegionRelations<'tcx>,
4042
) {
4143
let tcx = self.infcx.tcx;
4244

@@ -160,7 +162,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
160162
Locations::All,
161163
CustomTypeOp::new(
162164
|_cx| {
163-
infcx.constrain_anon_types(&anon_type_map, universal_regions);
165+
infcx.constrain_anon_types(&anon_type_map, universal_region_relations);
164166
Ok(InferOk {
165167
value: (),
166168
obligations: vec![],

0 commit comments

Comments
 (0)