Skip to content

Commit cafbd99

Browse files
committed
extend NLL regions to include free region indices and add outlives
1 parent 7b30e8d commit cafbd99

File tree

7 files changed

+297
-113
lines changed

7 files changed

+297
-113
lines changed

src/librustc_mir/dataflow/impls/borrows.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
3838
location_map: FxHashMap<Location, BorrowIndex>,
3939
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
4040
region_span_map: FxHashMap<RegionKind, Span>,
41-
nonlexical_regioncx: Option<&'a RegionInferenceContext>,
41+
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>,
4242
}
4343

4444
// temporarily allow some dead fields: `kind` and `region` will be
@@ -69,7 +69,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
6969
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
7070
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
7171
mir: &'a Mir<'tcx>,
72-
nonlexical_regioncx: Option<&'a RegionInferenceContext>)
72+
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>)
7373
-> Self {
7474
let mut visitor = GatherBorrows { idx_vec: IndexVec::new(),
7575
location_map: FxHashMap(),
@@ -140,7 +140,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
140140
if let Some(regioncx) = self.nonlexical_regioncx {
141141
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
142142
let borrow_region = regioncx.region_value(borrow_data.region.to_region_index());
143-
if !borrow_region.may_contain(location) && location != borrow_data.location {
143+
if !borrow_region.may_contain_point(location) && location != borrow_data.location {
144144
debug!("kill_loans_out_of_scope_at_location: kill{:?} \
145145
location={:?} borrow_data={:?}", borrow_index, location, borrow_data);
146146
sets.kill(&borrow_index);

src/librustc_mir/transform/nll/constraint_generation.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use super::region_infer::RegionInferenceContext;
2929

3030
pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
3131
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
32-
regioncx: &mut RegionInferenceContext,
32+
regioncx: &mut RegionInferenceContext<'tcx>,
3333
mir: &Mir<'tcx>,
3434
mir_source: MirSource,
3535
liveness: &LivenessResults,
@@ -45,7 +45,7 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
4545

4646
struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
4747
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
48-
regioncx: &'cx mut RegionInferenceContext,
48+
regioncx: &'cx mut RegionInferenceContext<'tcx>,
4949
mir: &'cx Mir<'tcx>,
5050
liveness: &'cx LivenessResults,
5151
mir_source: MirSource,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2017 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+
//! Code to extract the free regions declared on a function and the
12+
//! relationships between them. For example:
13+
//!
14+
//! ```
15+
//! fn foo<'a, 'b, 'c: 'b>() { }
16+
//! ```
17+
//!
18+
//! here we would be returning a map assigning each of `{'a, 'b, 'c}`
19+
//! to an index, as well as the `FreeRegionMap` which can compute
20+
//! relationships between them.
21+
//!
22+
//! The code in this file doesn't *do anything* with those results; it
23+
//! just returns them for other code to use.
24+
25+
use rustc::infer::InferCtxt;
26+
use rustc::middle::free_region::FreeRegionMap;
27+
use rustc::mir::transform::MirSource;
28+
use rustc::ty;
29+
use rustc::ty::subst::Substs;
30+
use rustc::util::nodemap::FxHashMap;
31+
32+
#[derive(Debug)]
33+
pub struct FreeRegions<'tcx> {
34+
/// Given a free region defined on this function (either early- or
35+
/// late-bound), this maps it to its internal region index. The
36+
/// corresponding variable will be "capped" so that it cannot
37+
/// grow.
38+
pub indices: FxHashMap<ty::Region<'tcx>, usize>,
39+
40+
/// The map from the typeck tables telling us how to relate free regions.
41+
pub free_region_map: &'tcx FreeRegionMap<'tcx>,
42+
}
43+
44+
pub fn free_regions<'a, 'gcx, 'tcx>(
45+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
46+
source: MirSource,
47+
) -> FreeRegions<'tcx> {
48+
debug!("free_regions(source={:?})", source);
49+
50+
let item_id = source.item_id();
51+
let item_def_id = infcx.tcx.hir.local_def_id(item_id);
52+
53+
let mut indices = FxHashMap();
54+
55+
// Extract the early regions.
56+
let item_substs = Substs::identity_for_item(infcx.tcx, item_def_id);
57+
for item_subst in item_substs {
58+
if let Some(region) = item_subst.as_region() {
59+
insert_free_region(&mut indices, region);
60+
}
61+
}
62+
63+
// Extract the late-bound regions. Use the liberated fn sigs,
64+
// where the late-bound regions will have been converted into free
65+
// regions, and add them to the map.
66+
let fn_hir_id = infcx.tcx.hir.node_to_hir_id(item_id);
67+
let tables = infcx.tcx.typeck_tables_of(item_def_id);
68+
let fn_sig = tables.liberated_fn_sigs()[fn_hir_id].clone();
69+
infcx
70+
.tcx
71+
.for_each_free_region(&fn_sig.inputs_and_output, |region| {
72+
if let ty::ReFree(_) = *region {
73+
insert_free_region(&mut indices, region);
74+
}
75+
});
76+
77+
debug!("free_regions: indices={:#?}", indices);
78+
79+
FreeRegions { indices, free_region_map: &tables.free_region_map }
80+
}
81+
82+
fn insert_free_region<'tcx>(
83+
free_regions: &mut FxHashMap<ty::Region<'tcx>, usize>,
84+
region: ty::Region<'tcx>,
85+
) {
86+
let len = free_regions.len();
87+
free_regions.entry(region).or_insert(len);
88+
}

src/librustc_mir/transform/nll/mod.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use util as mir_util;
2222
use self::mir_util::PassWhere;
2323

2424
mod constraint_generation;
25+
mod free_regions;
2526
mod subtype;
2627

2728
pub(crate) mod region_infer;
@@ -36,9 +37,12 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
3637
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
3738
source: MirSource,
3839
mir: &mut Mir<'tcx>,
39-
) -> RegionInferenceContext {
40+
) -> RegionInferenceContext<'tcx> {
41+
// Compute named region information.
42+
let free_regions = &free_regions::free_regions(infcx, source);
43+
4044
// Replace all regions with fresh inference variables.
41-
let num_region_variables = renumber::renumber_mir(infcx, mir);
45+
let num_region_variables = renumber::renumber_mir(infcx, free_regions, mir);
4246

4347
// Compute what is live where.
4448
let liveness = &LivenessResults {
@@ -61,11 +65,9 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
6165

6266
// Create the region inference context, generate the constraints,
6367
// and then solve them.
64-
let mut regioncx = RegionInferenceContext::new(num_region_variables);
68+
let mut regioncx = RegionInferenceContext::new(free_regions, num_region_variables, mir);
6569
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, source, liveness);
66-
let errors = regioncx.solve(infcx, &mir);
67-
68-
assert!(errors.is_empty(), "FIXME: report region inference failures");
70+
regioncx.solve(infcx, &mir);
6971

7072
// Dump MIR results into a file, if that is enabled. This let us
7173
// write unit-tests.
@@ -152,11 +154,15 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
152154
#[derive(Clone, Default, PartialEq, Eq)]
153155
pub struct Region {
154156
points: BTreeSet<Location>,
157+
free_regions: BTreeSet<RegionIndex>,
155158
}
156159

157160
impl fmt::Debug for Region {
158161
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
159-
write!(formatter, "{:?}", self.points)
162+
formatter.debug_set()
163+
.entries(&self.points)
164+
.entries(&self.free_regions)
165+
.finish()
160166
}
161167
}
162168

@@ -165,9 +171,17 @@ impl Region {
165171
self.points.insert(point)
166172
}
167173

168-
pub fn may_contain(&self, point: Location) -> bool {
174+
pub fn add_free_region(&mut self, region: RegionIndex) -> bool {
175+
self.free_regions.insert(region)
176+
}
177+
178+
pub fn may_contain_point(&self, point: Location) -> bool {
169179
self.points.contains(&point)
170180
}
181+
182+
pub fn may_contain_free_region(&self, region: RegionIndex) -> bool {
183+
self.free_regions.contains(&region)
184+
}
171185
}
172186

173187
newtype_index!(RegionIndex {

0 commit comments

Comments
 (0)