factor out NLL invocation interface

This commit is contained in:
Niko Matsakis 2017-10-25 12:09:01 -04:00
parent 7414060344
commit 5b2adcce11
2 changed files with 123 additions and 76 deletions

View file

@ -42,44 +42,70 @@ impl MirPass for NLL {
return;
}
tcx.infer_ctxt().enter(|ref infcx| {
// Clone mir so we can mutate it without disturbing the rest of the compiler
let mir = &mut input_mir.clone();
// Replace all regions with fresh inference variables.
let num_region_variables = renumber::renumber_mir(infcx, mir);
// Compute what is live where.
let liveness = &LivenessResults {
regular: liveness::liveness_of_locals(
mir,
LivenessMode {
include_regular_use: true,
include_drops: false,
},
),
drop: liveness::liveness_of_locals(
mir,
LivenessMode {
include_regular_use: false,
include_drops: true,
},
),
};
// Create the region inference context, generate the constraints,
// and then solve them.
let regioncx = &mut RegionInferenceContext::new(num_region_variables);
constraint_generation::generate_constraints(infcx, regioncx, mir, source, liveness);
regioncx.solve(infcx, mir);
// Dump MIR results into a file, if that is enabled.
dump_mir_results(infcx, liveness, source, regioncx, mir);
})
tcx.infer_ctxt()
.enter(|ref infcx| drop(compute_regions(infcx, source, input_mir)));
}
}
pub struct RegionComputation<'tcx> {
/// A rewritten version of the input MIR where all the regions are
/// rewritten to refer to inference variables.
pub mir: Mir<'tcx>,
/// The definitions (along with their final values) for all regions.
pub regioncx: RegionInferenceContext,
}
/// Computes the (non-lexical) regions from the input MIR.
///
/// This may result in errors being reported.
pub fn compute_regions<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
source: MirSource,
input_mir: &Mir<'tcx>,
) -> RegionComputation<'tcx> {
// Clone mir so we can mutate it without disturbing the rest of the compiler
let mut mir = input_mir.clone();
// Replace all regions with fresh inference variables.
let num_region_variables = renumber::renumber_mir(infcx, &mut mir);
// Compute what is live where.
let liveness = &LivenessResults {
regular: liveness::liveness_of_locals(
&mir,
LivenessMode {
include_regular_use: true,
include_drops: false,
},
),
drop: liveness::liveness_of_locals(
&mir,
LivenessMode {
include_regular_use: false,
include_drops: true,
},
),
};
// Create the region inference context, generate the constraints,
// and then solve them.
let mut regioncx = RegionInferenceContext::new(num_region_variables);
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, source, liveness);
let errors = regioncx.solve(infcx, &mir);
assert!(errors.is_empty(), "FIXME: report region inference failures");
let computation = RegionComputation { mir, regioncx };
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests.
dump_mir_results(infcx, liveness, source, &computation);
computation
}
struct LivenessResults {
regular: LivenessResult,
drop: LivenessResult,
@ -89,13 +115,17 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
liveness: &LivenessResults,
source: MirSource,
regioncx: &RegionInferenceContext,
mir: &Mir<'tcx>,
computation: &RegionComputation<'tcx>,
) {
if !mir_util::dump_enabled(infcx.tcx, "nll", source) {
return;
}
let RegionComputation {
ref mir,
ref regioncx,
} = *computation;
let regular_liveness_per_location: FxHashMap<_, _> = mir.basic_blocks()
.indices()
.flat_map(|bb| {
@ -126,7 +156,12 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
match pass_where {
// Before the CFG, dump out the values for each region variable.
PassWhere::BeforeCFG => for region in regioncx.regions() {
writeln!(out, "| {:?}: {:?}", region, regioncx.region_value(region))?;
writeln!(
out,
"| {:?}: {:?}",
region,
regioncx.region_value(region)
)?;
},
// Before each basic block, dump out the values
@ -141,12 +176,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
&regular_liveness_per_location[&location],
&drop_liveness_per_location[&location],
);
writeln!(
out,
" | Live variables at {:?}: {}",
location,
s
)?;
writeln!(out, " | Live variables at {:?}: {}", location, s)?;
}
PassWhere::AfterCFG => {}
@ -217,7 +247,11 @@ fn live_variable_set(regular: &LocalSet, drops: &LocalSet) -> String {
string.push_str(", ");
}
let len = if string.is_empty() { 0 } else { string.len() - 2 };
let len = if string.is_empty() {
0
} else {
string.len() - 2
};
format!("[{}]", &string[..len])
}

View file

@ -12,13 +12,22 @@ use super::{Region, RegionIndex};
use std::mem;
use rustc::infer::InferCtxt;
use rustc::mir::{Location, Mir};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashSet;
pub struct RegionInferenceContext {
definitions: IndexVec<RegionIndex, VarDefinition>,
constraints: IndexVec<ConstraintIndex, Constraint>,
errors: IndexVec<InferenceErrorIndex, InferenceError>,
/// Contains the definition for every region variable. Region
/// variables are identified by their index (`RegionIndex`). The
/// definition contains information about where the region came
/// from as well as its final inferred value.
definitions: IndexVec<RegionIndex, RegionDefinition>,
/// The constraints we have accumulated and used during solving.
constraints: Vec<Constraint>,
/// List of errors we have accumulated as we add constraints.
/// After solving is done, this is replaced with an empty vector.
errors: Vec<InferenceError>,
}
pub struct InferenceError {
@ -26,10 +35,8 @@ pub struct InferenceError {
pub name: (), // FIXME(nashenas88) RegionName
}
newtype_index!(InferenceErrorIndex);
#[derive(Default)]
struct VarDefinition {
struct RegionDefinition {
name: (), // FIXME(nashenas88) RegionName
value: Region,
capped: bool,
@ -42,26 +49,43 @@ pub struct Constraint {
point: Location,
}
newtype_index!(ConstraintIndex);
impl RegionInferenceContext {
pub fn new(num_region_variables: usize) -> Self {
Self {
definitions: (0..num_region_variables)
.map(|_| VarDefinition::default())
.map(|_| RegionDefinition::default())
.collect(),
constraints: IndexVec::new(),
errors: IndexVec::new(),
constraints: Vec::new(),
errors: Vec::new(),
}
}
/// Returns an iterator over all the region indices.
pub fn regions(&self) -> impl Iterator<Item = RegionIndex> {
self.definitions.indices()
}
/// Returns the inferred value for the region `r`.
///
/// Until `solve()` executes, this value is not particularly meaningful.
pub fn region_value(&self, r: RegionIndex) -> &Region {
&self.definitions[r].value
}
/// Flags a region as being "capped" -- this means that if its
/// value is required to grow as a result of some constraint
/// (e.g., `add_live_point` or `add_outlives`), that indicates an
/// error. This is used for the regions representing named
/// lifetime parameters on a function: they get initialized to
/// their complete value, and then "capped" so that they can no
/// longer grow.
#[allow(dead_code)]
pub fn cap_var(&mut self, v: RegionIndex) {
pub(super) fn cap_var(&mut self, v: RegionIndex) {
self.definitions[v].capped = true;
}
#[allow(dead_code)]
pub fn add_live_point(&mut self, v: RegionIndex, point: Location) {
pub(super) fn add_live_point(&mut self, v: RegionIndex, point: Location) {
debug!("add_live_point({:?}, {:?})", v, point);
let definition = &mut self.definitions[v];
if definition.value.add_point(point) {
@ -74,28 +98,17 @@ impl RegionInferenceContext {
}
}
#[allow(dead_code)]
pub fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
pub(super) fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
self.constraints.push(Constraint { sup, sub, point });
}
/// Returns an iterator over all the region indices.
pub fn regions(&self) -> impl Iterator<Item = RegionIndex> {
self.definitions.indices()
}
/// Returns the current value for the region `v`. This is only
/// really meaningful after `solve` has executed.
pub fn region_value(&self, v: RegionIndex) -> &Region {
&self.definitions[v].value
}
pub fn solve<'a, 'gcx, 'tcx>(
/// Perform region inference.
pub(super) fn solve<'a, 'gcx, 'tcx>(
&mut self,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
mir: &'a Mir<'tcx>,
) -> IndexVec<InferenceErrorIndex, InferenceError>
) -> Vec<InferenceError>
where
'gcx: 'tcx + 'a,
'tcx: 'a,
@ -138,7 +151,7 @@ impl RegionInferenceContext {
debug!("\n");
}
mem::replace(&mut self.errors, IndexVec::new())
mem::replace(&mut self.errors, Vec::new())
}
}