]> git.lizzy.rs Git - rust.git/commitdiff
factor out NLL invocation interface
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 25 Oct 2017 16:09:01 +0000 (12:09 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 31 Oct 2017 16:41:39 +0000 (12:41 -0400)
src/librustc_mir/transform/nll/mod.rs
src/librustc_mir/transform/nll/region_infer.rs

index 1498a6b23c094d07d6c1ea9d54857921f8c26a66..8a62533ba337f538d9037c345524857e762c7293 100644 (file)
@@ -42,44 +42,70 @@ fn run_pass<'a, 'tcx>(
             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])
 }
index 75abd4d3ff53a1b0c59f83e1741e36a69335da5c..c23d73e784ae9d04b4325e244feab9f66d95b5ef 100644 (file)
 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 @@ pub fn add_live_point(&mut self, v: RegionIndex, point: Location) {
         }
     }
 
-    #[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 @@ pub fn solve<'a, 'gcx, 'tcx>(
             debug!("\n");
         }
 
-        mem::replace(&mut self.errors, IndexVec::new())
+        mem::replace(&mut self.errors, Vec::new())
     }
 }