Skip to content

Commit cc2a1c7

Browse files
Nashenas88Paul Daniel Faria
authored andcommitted
Initial attempt at implementation of inference layout for nll
1 parent 43d95e2 commit cc2a1c7

File tree

2 files changed

+224
-5
lines changed

2 files changed

+224
-5
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
use super::{Region, RegionIndex};
2+
use std::mem;
3+
use rustc::infer::InferCtxt;
4+
use rustc::mir::{Location, Mir};
5+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
6+
use rustc_data_structures::fx::FxHashSet;
7+
8+
pub struct InferenceContext {
9+
definitions: IndexVec<RegionIndex, VarDefinition>,
10+
constraints: IndexVec<ConstraintIndex, Constraint>,
11+
errors: IndexVec<InferenceErrorIndex, InferenceError>,
12+
}
13+
14+
pub struct InferenceError {
15+
pub constraint_point: Location,
16+
pub name: (), // TODO(nashenas88) RegionName
17+
}
18+
19+
newtype_index!(InferenceErrorIndex);
20+
21+
struct VarDefinition {
22+
name: (), // TODO(nashenas88) RegionName
23+
value: Region,
24+
capped: bool,
25+
}
26+
27+
impl VarDefinition {
28+
pub fn new(value: Region) -> Self {
29+
Self {
30+
name: (),
31+
value,
32+
capped: false,
33+
}
34+
}
35+
}
36+
37+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
38+
pub struct Constraint {
39+
sub: RegionIndex,
40+
sup: RegionIndex,
41+
point: Location,
42+
}
43+
44+
newtype_index!(ConstraintIndex);
45+
46+
impl InferenceContext {
47+
pub fn new(values: IndexVec<RegionIndex, Region>) -> Self {
48+
Self {
49+
definitions: values.into_iter().map(VarDefinition::new).collect(),
50+
constraints: IndexVec::new(),
51+
errors: IndexVec::new(),
52+
}
53+
}
54+
55+
pub fn cap_var(&mut self, v: RegionIndex) {
56+
self.definitions[v].capped = true;
57+
}
58+
59+
pub fn add_live_point(&mut self, v: RegionIndex, point: Location) {
60+
debug!("add_live_point({:?}, {:?})", v, point);
61+
let definition = &mut self.definitions[v];
62+
if definition.value.add_point(point) {
63+
if definition.capped {
64+
self.errors.push(InferenceError {
65+
constraint_point: point,
66+
name: definition.name,
67+
});
68+
}
69+
}
70+
}
71+
72+
pub fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
73+
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
74+
self.constraints.push(Constraint { sup, sub, point });
75+
}
76+
77+
pub fn region(&self, v: RegionIndex) -> &Region {
78+
&self.definitions[v].value
79+
}
80+
81+
pub fn solve<'a, 'gcx, 'tcx>(
82+
&mut self,
83+
infcx: InferCtxt<'a, 'gcx, 'tcx>,
84+
mir: &'a Mir<'tcx>,
85+
) -> IndexVec<InferenceErrorIndex, InferenceError>
86+
where
87+
'gcx: 'tcx + 'a,
88+
'tcx: 'a,
89+
{
90+
let mut changed = true;
91+
let mut dfs = Dfs::new(infcx, mir);
92+
while changed {
93+
changed = false;
94+
for constraint in &self.constraints {
95+
let sub = &self.definitions[constraint.sub].value.clone();
96+
let sup_def = &self.definitions[constraint.sup];
97+
debug!("constraint: {:?}", constraint);
98+
debug!(" sub (before): {:?}", sub);
99+
debug!(" sup (before): {:?}", sup_def.value);
100+
101+
if dfs.copy(sub, &mut sup_def.value, constraint.point) {
102+
changed = true;
103+
if sup_def.capped {
104+
// This is kind of a hack, but when we add a
105+
// constraint, the "point" is always the point
106+
// AFTER the action that induced the
107+
// constraint. So report the error on the
108+
// action BEFORE that.
109+
assert!(constraint.point.statement_index > 0);
110+
let p = Location {
111+
block: constraint.point.block,
112+
statement_index: constraint.point.statement_index - 1,
113+
};
114+
115+
self.errors.push(InferenceError {
116+
constraint_point: p,
117+
name: sup_def.name,
118+
});
119+
}
120+
}
121+
122+
debug!(" sup (after) : {:?}", sup_def.value);
123+
debug!(" changed : {:?}", changed);
124+
}
125+
debug!("\n");
126+
}
127+
128+
mem::replace(&mut self.errors, IndexVec::new())
129+
}
130+
}
131+
132+
struct Dfs<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
133+
infcx: InferCtxt<'a, 'gcx, 'tcx>,
134+
mir: &'a Mir<'tcx>,
135+
}
136+
137+
impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
138+
fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
139+
Self { infcx, mir }
140+
}
141+
142+
fn copy(
143+
&mut self,
144+
from_region: &Region,
145+
to_region: &mut Region,
146+
start_point: Location,
147+
) -> bool {
148+
let mut changed = false;
149+
150+
let mut stack = vec![];
151+
let mut visited = FxHashSet();
152+
153+
stack.push(start_point);
154+
while let Some(p) = stack.pop() {
155+
debug!(" dfs: p={:?}", p);
156+
157+
if !from_region.may_contain(p) {
158+
debug!(" not in from-region");
159+
continue;
160+
}
161+
162+
if !visited.insert(p) {
163+
debug!(" already visited");
164+
continue;
165+
}
166+
167+
changed |= to_region.add_point(p);
168+
169+
let block_data = self.mir[p.block];
170+
let successor_points = if p.statement_index < block_data.statements.len() {
171+
vec![Location {
172+
statement_index: p.statement_index + 1,
173+
..p
174+
}]
175+
} else {
176+
block_data.terminator()
177+
.successors()
178+
.iter()
179+
.map(|&basic_block| Location {
180+
statement_index: 0,
181+
block: basic_block,
182+
})
183+
.collect::<Vec<_>>()
184+
};
185+
186+
if successor_points.is_empty() {
187+
// If we reach the END point in the graph, then copy
188+
// over any skolemized end points in the `from_region`
189+
// and make sure they are included in the `to_region`.
190+
for region_decl in self.infcx.tcx.tables.borrow().free_region_map() {
191+
// TODO(nashenas88) figure out skolemized_end points
192+
let block = self.env.graph.skolemized_end(region_decl.name);
193+
let skolemized_end_point = Location {
194+
block,
195+
statement_index: 0,
196+
};
197+
changed |= to_region.add_point(skolemized_end_point);
198+
}
199+
} else {
200+
stack.extend(successor_points);
201+
}
202+
}
203+
204+
changed
205+
}
206+
}

src/librustc_mir/transform/nll/mod.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use self::infer::InferenceContext;
1112
use rustc::ty::TypeFoldable;
1213
use rustc::ty::subst::{Kind, Substs};
1314
use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind};
1415
use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind};
1516
use rustc::mir::visit::{MutVisitor, Lookup};
1617
use rustc::mir::transform::{MirPass, MirSource};
17-
use rustc::infer::{self, InferCtxt};
18+
use rustc::infer::{self as rustc_infer, InferCtxt};
1819
use rustc::util::nodemap::FxHashSet;
1920
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
2021
use syntax_pos::DUMMY_SP;
@@ -24,6 +25,8 @@ use std::fmt;
2425
use util as mir_util;
2526
use self::mir_util::PassWhere;
2627

28+
mod infer;
29+
2730
#[allow(dead_code)]
2831
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
2932
lookup_map: HashMap<RegionVid, Lookup>,
@@ -40,14 +43,14 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
4043
}
4144
}
4245

43-
pub fn into_results(self) -> HashMap<RegionVid, Lookup> {
44-
self.lookup_map
46+
pub fn into_results(self) -> (HashMap<RegionVid, Lookup>, IndexVec<RegionIndex, Region>) {
47+
(self.lookup_map, self.regions)
4548
}
4649

4750
fn renumber_regions<T>(&mut self, value: &T) -> T where T: TypeFoldable<'tcx> {
4851
self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
4952
self.regions.push(Region::default());
50-
self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP))
53+
self.infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP))
5154
})
5255
}
5356

@@ -157,7 +160,9 @@ impl MirPass for NLL {
157160
}
158161
Ok(())
159162
});
160-
let _results = visitor.into_results();
163+
let (_lookup_map, regions) = visitor.into_results();
164+
let inference_context = InferenceContext::new(regions);
165+
inference_context.solve(infcx, &renumbered_mir);
161166
})
162167
}
163168
}
@@ -173,6 +178,14 @@ impl fmt::Debug for Region {
173178
}
174179
}
175180

181+
impl Region {
182+
pub fn add_point(&mut self, point: Location) -> bool {
183+
self.points.insert(point)
184+
}
176185

186+
pub fn may_contain(&self, point: Location) -> bool {
187+
self.points.contains(&point)
188+
}
189+
}
177190

178191
newtype_index!(RegionIndex);

0 commit comments

Comments
 (0)