Skip to content

Commit 5b2adcc

Browse files
committed
factor out NLL invocation interface
1 parent 7414060 commit 5b2adcc

File tree

2 files changed

+123
-76
lines changed

2 files changed

+123
-76
lines changed

src/librustc_mir/transform/nll/mod.rs

Lines changed: 79 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -42,44 +42,70 @@ impl MirPass for NLL {
4242
return;
4343
}
4444

45-
tcx.infer_ctxt().enter(|ref infcx| {
46-
// Clone mir so we can mutate it without disturbing the rest of the compiler
47-
let mir = &mut input_mir.clone();
48-
49-
// Replace all regions with fresh inference variables.
50-
let num_region_variables = renumber::renumber_mir(infcx, mir);
51-
52-
// Compute what is live where.
53-
let liveness = &LivenessResults {
54-
regular: liveness::liveness_of_locals(
55-
mir,
56-
LivenessMode {
57-
include_regular_use: true,
58-
include_drops: false,
59-
},
60-
),
61-
62-
drop: liveness::liveness_of_locals(
63-
mir,
64-
LivenessMode {
65-
include_regular_use: false,
66-
include_drops: true,
67-
},
68-
),
69-
};
70-
71-
// Create the region inference context, generate the constraints,
72-
// and then solve them.
73-
let regioncx = &mut RegionInferenceContext::new(num_region_variables);
74-
constraint_generation::generate_constraints(infcx, regioncx, mir, source, liveness);
75-
regioncx.solve(infcx, mir);
76-
77-
// Dump MIR results into a file, if that is enabled.
78-
dump_mir_results(infcx, liveness, source, regioncx, mir);
79-
})
45+
tcx.infer_ctxt()
46+
.enter(|ref infcx| drop(compute_regions(infcx, source, input_mir)));
8047
}
8148
}
8249

50+
pub struct RegionComputation<'tcx> {
51+
/// A rewritten version of the input MIR where all the regions are
52+
/// rewritten to refer to inference variables.
53+
pub mir: Mir<'tcx>,
54+
55+
/// The definitions (along with their final values) for all regions.
56+
pub regioncx: RegionInferenceContext,
57+
}
58+
59+
/// Computes the (non-lexical) regions from the input MIR.
60+
///
61+
/// This may result in errors being reported.
62+
pub fn compute_regions<'a, 'gcx, 'tcx>(
63+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
64+
source: MirSource,
65+
input_mir: &Mir<'tcx>,
66+
) -> RegionComputation<'tcx> {
67+
// Clone mir so we can mutate it without disturbing the rest of the compiler
68+
let mut mir = input_mir.clone();
69+
70+
// Replace all regions with fresh inference variables.
71+
let num_region_variables = renumber::renumber_mir(infcx, &mut mir);
72+
73+
// Compute what is live where.
74+
let liveness = &LivenessResults {
75+
regular: liveness::liveness_of_locals(
76+
&mir,
77+
LivenessMode {
78+
include_regular_use: true,
79+
include_drops: false,
80+
},
81+
),
82+
83+
drop: liveness::liveness_of_locals(
84+
&mir,
85+
LivenessMode {
86+
include_regular_use: false,
87+
include_drops: true,
88+
},
89+
),
90+
};
91+
92+
// Create the region inference context, generate the constraints,
93+
// and then solve them.
94+
let mut regioncx = RegionInferenceContext::new(num_region_variables);
95+
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, source, liveness);
96+
let errors = regioncx.solve(infcx, &mir);
97+
98+
assert!(errors.is_empty(), "FIXME: report region inference failures");
99+
100+
let computation = RegionComputation { mir, regioncx };
101+
102+
// Dump MIR results into a file, if that is enabled. This let us
103+
// write unit-tests.
104+
dump_mir_results(infcx, liveness, source, &computation);
105+
106+
computation
107+
}
108+
83109
struct LivenessResults {
84110
regular: LivenessResult,
85111
drop: LivenessResult,
@@ -89,13 +115,17 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
89115
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
90116
liveness: &LivenessResults,
91117
source: MirSource,
92-
regioncx: &RegionInferenceContext,
93-
mir: &Mir<'tcx>,
118+
computation: &RegionComputation<'tcx>,
94119
) {
95120
if !mir_util::dump_enabled(infcx.tcx, "nll", source) {
96121
return;
97122
}
98123

124+
let RegionComputation {
125+
ref mir,
126+
ref regioncx,
127+
} = *computation;
128+
99129
let regular_liveness_per_location: FxHashMap<_, _> = mir.basic_blocks()
100130
.indices()
101131
.flat_map(|bb| {
@@ -126,7 +156,12 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
126156
match pass_where {
127157
// Before the CFG, dump out the values for each region variable.
128158
PassWhere::BeforeCFG => for region in regioncx.regions() {
129-
writeln!(out, "| {:?}: {:?}", region, regioncx.region_value(region))?;
159+
writeln!(
160+
out,
161+
"| {:?}: {:?}",
162+
region,
163+
regioncx.region_value(region)
164+
)?;
130165
},
131166

132167
// Before each basic block, dump out the values
@@ -141,12 +176,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
141176
&regular_liveness_per_location[&location],
142177
&drop_liveness_per_location[&location],
143178
);
144-
writeln!(
145-
out,
146-
" | Live variables at {:?}: {}",
147-
location,
148-
s
149-
)?;
179+
writeln!(out, " | Live variables at {:?}: {}", location, s)?;
150180
}
151181

152182
PassWhere::AfterCFG => {}
@@ -217,7 +247,11 @@ fn live_variable_set(regular: &LocalSet, drops: &LocalSet) -> String {
217247
string.push_str(", ");
218248
}
219249

220-
let len = if string.is_empty() { 0 } else { string.len() - 2 };
250+
let len = if string.is_empty() {
251+
0
252+
} else {
253+
string.len() - 2
254+
};
221255

222256
format!("[{}]", &string[..len])
223257
}

src/librustc_mir/transform/nll/region_infer.rs

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,31 @@ use super::{Region, RegionIndex};
1212
use std::mem;
1313
use rustc::infer::InferCtxt;
1414
use rustc::mir::{Location, Mir};
15-
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
15+
use rustc_data_structures::indexed_vec::IndexVec;
1616
use rustc_data_structures::fx::FxHashSet;
1717

1818
pub struct RegionInferenceContext {
19-
definitions: IndexVec<RegionIndex, VarDefinition>,
20-
constraints: IndexVec<ConstraintIndex, Constraint>,
21-
errors: IndexVec<InferenceErrorIndex, InferenceError>,
19+
/// Contains the definition for every region variable. Region
20+
/// variables are identified by their index (`RegionIndex`). The
21+
/// definition contains information about where the region came
22+
/// from as well as its final inferred value.
23+
definitions: IndexVec<RegionIndex, RegionDefinition>,
24+
25+
/// The constraints we have accumulated and used during solving.
26+
constraints: Vec<Constraint>,
27+
28+
/// List of errors we have accumulated as we add constraints.
29+
/// After solving is done, this is replaced with an empty vector.
30+
errors: Vec<InferenceError>,
2231
}
2332

2433
pub struct InferenceError {
2534
pub constraint_point: Location,
2635
pub name: (), // FIXME(nashenas88) RegionName
2736
}
2837

29-
newtype_index!(InferenceErrorIndex);
30-
3138
#[derive(Default)]
32-
struct VarDefinition {
39+
struct RegionDefinition {
3340
name: (), // FIXME(nashenas88) RegionName
3441
value: Region,
3542
capped: bool,
@@ -42,26 +49,43 @@ pub struct Constraint {
4249
point: Location,
4350
}
4451

45-
newtype_index!(ConstraintIndex);
46-
4752
impl RegionInferenceContext {
4853
pub fn new(num_region_variables: usize) -> Self {
4954
Self {
5055
definitions: (0..num_region_variables)
51-
.map(|_| VarDefinition::default())
56+
.map(|_| RegionDefinition::default())
5257
.collect(),
53-
constraints: IndexVec::new(),
54-
errors: IndexVec::new(),
58+
constraints: Vec::new(),
59+
errors: Vec::new(),
5560
}
5661
}
5762

63+
64+
/// Returns an iterator over all the region indices.
65+
pub fn regions(&self) -> impl Iterator<Item = RegionIndex> {
66+
self.definitions.indices()
67+
}
68+
69+
/// Returns the inferred value for the region `r`.
70+
///
71+
/// Until `solve()` executes, this value is not particularly meaningful.
72+
pub fn region_value(&self, r: RegionIndex) -> &Region {
73+
&self.definitions[r].value
74+
}
75+
76+
/// Flags a region as being "capped" -- this means that if its
77+
/// value is required to grow as a result of some constraint
78+
/// (e.g., `add_live_point` or `add_outlives`), that indicates an
79+
/// error. This is used for the regions representing named
80+
/// lifetime parameters on a function: they get initialized to
81+
/// their complete value, and then "capped" so that they can no
82+
/// longer grow.
5883
#[allow(dead_code)]
59-
pub fn cap_var(&mut self, v: RegionIndex) {
84+
pub(super) fn cap_var(&mut self, v: RegionIndex) {
6085
self.definitions[v].capped = true;
6186
}
6287

63-
#[allow(dead_code)]
64-
pub fn add_live_point(&mut self, v: RegionIndex, point: Location) {
88+
pub(super) fn add_live_point(&mut self, v: RegionIndex, point: Location) {
6589
debug!("add_live_point({:?}, {:?})", v, point);
6690
let definition = &mut self.definitions[v];
6791
if definition.value.add_point(point) {
@@ -74,28 +98,17 @@ impl RegionInferenceContext {
7498
}
7599
}
76100

77-
#[allow(dead_code)]
78-
pub fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
101+
pub(super) fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
79102
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
80103
self.constraints.push(Constraint { sup, sub, point });
81104
}
82105

83-
/// Returns an iterator over all the region indices.
84-
pub fn regions(&self) -> impl Iterator<Item = RegionIndex> {
85-
self.definitions.indices()
86-
}
87-
88-
/// Returns the current value for the region `v`. This is only
89-
/// really meaningful after `solve` has executed.
90-
pub fn region_value(&self, v: RegionIndex) -> &Region {
91-
&self.definitions[v].value
92-
}
93-
94-
pub fn solve<'a, 'gcx, 'tcx>(
106+
/// Perform region inference.
107+
pub(super) fn solve<'a, 'gcx, 'tcx>(
95108
&mut self,
96109
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
97110
mir: &'a Mir<'tcx>,
98-
) -> IndexVec<InferenceErrorIndex, InferenceError>
111+
) -> Vec<InferenceError>
99112
where
100113
'gcx: 'tcx + 'a,
101114
'tcx: 'a,
@@ -138,7 +151,7 @@ impl RegionInferenceContext {
138151
debug!("\n");
139152
}
140153

141-
mem::replace(&mut self.errors, IndexVec::new())
154+
mem::replace(&mut self.errors, Vec::new())
142155
}
143156
}
144157

0 commit comments

Comments
 (0)