Skip to content

Commit 3bca170

Browse files
nikomatsakispnkfelix
authored andcommitted
introduce, but do not use, free_region_relation computation
This duplicates, effectively, existing code in the universal regions computation.
1 parent 54628c8 commit 3bca170

File tree

5 files changed

+243
-4
lines changed

5 files changed

+243
-4
lines changed

src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
104104
None
105105
};
106106

107+
let universal_regions = Rc::new(universal_regions);
108+
107109
let elements = &Rc::new(RegionValueElements::new(mir));
108110

109111
// Run the MIR type-checker.

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
206206
/// of constraints produced by the MIR type check.
207207
pub(crate) fn new(
208208
var_infos: VarInfos,
209-
universal_regions: UniversalRegions<'tcx>,
209+
universal_regions: Rc<UniversalRegions<'tcx>>,
210210
_mir: &Mir<'tcx>,
211211
outlives_constraints: ConstraintSet,
212212
type_tests: Vec<TypeTest<'tcx>>,
213213
liveness_constraints: LivenessValues<RegionVid>,
214214
elements: &Rc<RegionValueElements>,
215215
) -> Self {
216-
let universal_regions = Rc::new(universal_regions);
217-
218216
// Create a RegionDefinition for each inference variable.
219217
let definitions: IndexVec<_, _> = var_infos
220218
.into_iter()
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use borrow_check::location::LocationTable;
12+
use borrow_check::nll::facts::AllFacts;
13+
use borrow_check::nll::universal_regions::UniversalRegions;
14+
use borrow_check::nll::type_check::constraint_conversion;
15+
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
16+
use rustc::hir::def_id::DefId;
17+
use rustc::infer::region_constraints::GenericKind;
18+
use rustc::infer::InferCtxt;
19+
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
20+
use rustc::traits::query::type_op::{self, TypeOp};
21+
use rustc::ty::{self, RegionVid, Ty};
22+
use rustc_data_structures::transitive_relation::TransitiveRelation;
23+
use std::rc::Rc;
24+
use syntax::ast;
25+
26+
#[derive(Debug)]
27+
crate struct UniversalRegionRelations<'tcx> {
28+
universal_regions: Rc<UniversalRegions<'tcx>>,
29+
30+
/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
31+
/// be true. These encode relationships like `T: 'a` that are
32+
/// added via implicit bounds.
33+
///
34+
/// Each region here is guaranteed to be a key in the `indices`
35+
/// map. We use the "original" regions (i.e., the keys from the
36+
/// map, and not the values) because the code in
37+
/// `process_registered_region_obligations` has some special-cased
38+
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
39+
/// our special inference variable there, we would mess that up.
40+
crate region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
41+
42+
/// Stores the outlives relations that are known to hold from the
43+
/// implied bounds, in-scope where clauses, and that sort of
44+
/// thing.
45+
outlives: TransitiveRelation<RegionVid>,
46+
47+
/// This is the `<=` relation; that is, if `a: b`, then `b <= a`,
48+
/// and we store that here. This is useful when figuring out how
49+
/// to express some local region in terms of external regions our
50+
/// caller will understand.
51+
inverse_outlives: TransitiveRelation<RegionVid>,
52+
}
53+
54+
impl UniversalRegionRelations<'tcx> {
55+
crate fn create(
56+
infcx: &InferCtxt<'_, '_, 'tcx>,
57+
mir_def_id: DefId,
58+
param_env: ty::ParamEnv<'tcx>,
59+
location_table: &LocationTable,
60+
implicit_region_bound: Option<ty::Region<'tcx>>,
61+
universal_regions: &Rc<UniversalRegions<'tcx>>,
62+
constraints: &mut MirTypeckRegionConstraints<'tcx>,
63+
all_facts: &mut Option<AllFacts>,
64+
) -> Self {
65+
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
66+
UniversalRegionRelationsBuilder {
67+
infcx,
68+
mir_def_id,
69+
mir_node_id,
70+
param_env,
71+
implicit_region_bound,
72+
constraints,
73+
location_table,
74+
all_facts,
75+
universal_regions: universal_regions.clone(),
76+
relations: UniversalRegionRelations {
77+
universal_regions: universal_regions.clone(),
78+
region_bound_pairs: Vec::new(),
79+
outlives: TransitiveRelation::new(),
80+
inverse_outlives: TransitiveRelation::new(),
81+
},
82+
}.create()
83+
}
84+
85+
/// Records in the `outlives_relation` (and
86+
/// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
87+
/// builder below.
88+
fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
89+
debug!(
90+
"relate_universal_regions: fr_a={:?} outlives fr_b={:?}",
91+
fr_a, fr_b
92+
);
93+
self.outlives.add(fr_a, fr_b);
94+
self.inverse_outlives.add(fr_b, fr_a);
95+
}
96+
}
97+
98+
struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
99+
infcx: &'this InferCtxt<'this, 'gcx, 'tcx>,
100+
mir_def_id: DefId,
101+
mir_node_id: ast::NodeId,
102+
param_env: ty::ParamEnv<'tcx>,
103+
location_table: &'this LocationTable,
104+
universal_regions: Rc<UniversalRegions<'tcx>>,
105+
relations: UniversalRegionRelations<'tcx>,
106+
implicit_region_bound: Option<ty::Region<'tcx>>,
107+
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
108+
all_facts: &'this mut Option<AllFacts>,
109+
}
110+
111+
impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
112+
crate fn create(mut self) -> UniversalRegionRelations<'tcx> {
113+
let unnormalized_input_output_tys = self
114+
.universal_regions
115+
.unnormalized_input_tys
116+
.iter()
117+
.cloned()
118+
.chain(Some(self.universal_regions.unnormalized_output_ty));
119+
120+
// For each of the input/output types:
121+
// - Normalize the type. This will create some region
122+
// constraints, which we buffer up because we are
123+
// not ready to process them yet.
124+
// - Then compute the implied bounds. This will adjust
125+
// the `relations.region_bound_pairs` and so forth.
126+
// - After this is done, we'll process the constraints, once
127+
// the `relations` is built.
128+
let constraint_sets: Vec<_> = unnormalized_input_output_tys
129+
.flat_map(|ty| {
130+
debug!("build: input_or_output={:?}", ty);
131+
let (ty, constraints) = self
132+
.param_env
133+
.and(type_op::normalize::Normalize::new(ty))
134+
.fully_perform(self.infcx)
135+
.unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
136+
self.add_implied_bounds(ty);
137+
constraints
138+
})
139+
.collect();
140+
141+
// Insert the facts we know from the predicates. Why? Why not.
142+
let param_env = self.param_env;
143+
self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env));
144+
145+
// Finally:
146+
// - outlives is reflexive, so `'r: 'r` for every region `'r`
147+
// - `'static: 'r` for every region `'r`
148+
// - `'r: 'fn_body` for every (other) universally quantified
149+
// region `'r`, all of which are provided by our caller
150+
let fr_static = self.universal_regions.fr_static;
151+
let fr_fn_body = self.universal_regions.fr_fn_body;
152+
for fr in self.universal_regions.universal_regions() {
153+
debug!(
154+
"build: relating free region {:?} to itself and to 'static",
155+
fr
156+
);
157+
self.relations.relate_universal_regions(fr, fr);
158+
self.relations.relate_universal_regions(fr_static, fr);
159+
self.relations.relate_universal_regions(fr, fr_fn_body);
160+
}
161+
162+
for data in constraint_sets {
163+
constraint_conversion::ConstraintConversion::new(
164+
self.infcx.tcx,
165+
&self.universal_regions,
166+
&self.location_table,
167+
&self.relations.region_bound_pairs,
168+
self.implicit_region_bound,
169+
self.param_env,
170+
Locations::All,
171+
&mut self.constraints.outlives_constraints,
172+
&mut self.constraints.type_tests,
173+
&mut self.all_facts,
174+
).convert_all(&data);
175+
}
176+
177+
self.relations
178+
}
179+
180+
/// Update the type of a single local, which should represent
181+
/// either the return type of the MIR or one of its arguments. At
182+
/// the same time, compute and add any implied bounds that come
183+
/// from this local.
184+
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) {
185+
debug!("add_implied_bounds(ty={:?})", ty);
186+
let span = self.infcx.tcx.def_span(self.mir_def_id);
187+
let bounds = self
188+
.infcx
189+
.implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span);
190+
self.add_outlives_bounds(bounds);
191+
}
192+
193+
/// Registers the `OutlivesBound` items from `outlives_bounds` in
194+
/// the outlives relation as well as the region-bound pairs
195+
/// listing.
196+
fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
197+
where
198+
I: IntoIterator<Item = OutlivesBound<'tcx>>,
199+
{
200+
for outlives_bound in outlives_bounds {
201+
debug!("add_outlives_bounds(bound={:?})", outlives_bound);
202+
203+
match outlives_bound {
204+
OutlivesBound::RegionSubRegion(r1, r2) => {
205+
// The bound says that `r1 <= r2`; we store `r2: r1`.
206+
let r1 = self.universal_regions.to_region_vid(r1);
207+
let r2 = self.universal_regions.to_region_vid(r2);
208+
self.relations.relate_universal_regions(r2, r1);
209+
}
210+
211+
OutlivesBound::RegionSubParam(r_a, param_b) => {
212+
self.relations
213+
.region_bound_pairs
214+
.push((r_a, GenericKind::Param(param_b)));
215+
}
216+
217+
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
218+
self.relations
219+
.region_bound_pairs
220+
.push((r_a, GenericKind::Projection(projection_b)));
221+
}
222+
}
223+
}
224+
}
225+
}

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ macro_rules! span_mirbug_and_err {
7171
}
7272

7373
mod constraint_conversion;
74+
mod free_region_relations;
7475
mod input_output;
7576
mod liveness;
7677
mod relate_tys;
@@ -110,7 +111,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
110111
param_env: ty::ParamEnv<'gcx>,
111112
mir: &Mir<'tcx>,
112113
mir_def_id: DefId,
113-
universal_regions: &UniversalRegions<'tcx>,
114+
universal_regions: &Rc<UniversalRegions<'tcx>>,
114115
location_table: &LocationTable,
115116
borrow_set: &BorrowSet<'tcx>,
116117
liveness: &LivenessResults<LocalWithRegion>,
@@ -127,6 +128,17 @@ pub(crate) fn type_check<'gcx, 'tcx>(
127128
type_tests: Vec::default(),
128129
};
129130

131+
let _urr = free_region_relations::UniversalRegionRelations::create(
132+
infcx,
133+
mir_def_id,
134+
param_env,
135+
location_table,
136+
Some(implicit_region_bound),
137+
universal_regions,
138+
&mut constraints,
139+
all_facts,
140+
);
141+
130142
{
131143
let mut borrowck_context = BorrowCheckContext {
132144
universal_regions,

src/librustc_mir/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
1414
1515
*/
1616

17+
#![feature(infer_outlives_requirements)]
18+
#![feature(in_band_lifetimes)]
1719
#![feature(slice_patterns)]
1820
#![feature(slice_sort_by_cached_key)]
1921
#![feature(from_ref)]

0 commit comments

Comments
 (0)