factor out NLL invocation interface
This commit is contained in:
parent
7414060344
commit
5b2adcce11
2 changed files with 123 additions and 76 deletions
|
|
@ -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>(
|
|||
®ular_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])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue