]> git.lizzy.rs Git - rust.git/commitdiff
formalize giving ownership of region vars to region inf. context
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 6 Nov 2017 10:21:48 +0000 (05:21 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Thu, 16 Nov 2017 10:57:46 +0000 (05:57 -0500)
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/mod.rs
src/librustc/mir/visit.rs
src/librustc_mir/transform/nll/mod.rs
src/librustc_mir/transform/nll/region_infer.rs
src/librustc_mir/transform/nll/renumber.rs
src/librustc_mir/transform/type_check.rs

index 67fdd68a826c2573d99052b32a8d6072de0a1c01..84baece77fe591548ded0b094d16a80b595be4a6 100644 (file)
@@ -1029,6 +1029,7 @@ fn report_inference_failure(&self,
                 let var_name = self.tcx.hir.name(var_node_id);
                 format!(" for capture of `{}` by closure", var_name)
             }
+            infer::NLL(..) => bug!("NLL variable found in lexical phase"),
         };
 
         struct_span_err!(self.tcx.sess, var_origin.span(), E0495,
index 10734802a6d0e4688505b1bdae0bbec46caa8895..2b080c54da1f311e0436cf08d847e7a2732dcdbb 100644 (file)
@@ -16,7 +16,6 @@
 pub use self::ValuePairs::*;
 pub use ty::IntVarValue;
 pub use self::freshen::TypeFreshener;
-pub use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData};
 
 use hir::def_id::DefId;
 use middle::free_region::{FreeRegionMap, RegionRelations};
@@ -25,7 +24,7 @@
 use mir::tcx::LvalueTy;
 use ty::subst::{Kind, Subst, Substs};
 use ty::{TyVid, IntVid, FloatVid};
-use ty::{self, RegionVid, Ty, TyCtxt};
+use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::relate::RelateResult;
@@ -42,6 +41,7 @@
 use self::combine::CombineFields;
 use self::higher_ranked::HrMatchResult;
 use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
+use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarOrigins};
 use self::lexical_region_resolve::LexicalRegionResolutions;
 use self::type_variable::TypeVariableOrigin;
 use self::unify_key::ToType;
@@ -321,7 +321,7 @@ pub enum LateBoundRegionConversionTime {
 /// Reasons to create a region inference variable
 ///
 /// See `error_reporting` module for more details
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
 pub enum RegionVariableOrigin {
     // Region variables created for ill-categorized reasons,
     // mostly indicates places in need of refactoring
@@ -349,6 +349,20 @@ pub enum RegionVariableOrigin {
     UpvarRegion(ty::UpvarId, Span),
 
     BoundRegionInCoherence(ast::Name),
+
+    // This origin is used for the inference variables that we create
+    // during NLL region processing.
+    NLL(NLLRegionVariableOrigin),
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum NLLRegionVariableOrigin {
+    // During NLL region processing, we create variables for free
+    // regions that we encounter in the function signature and
+    // elsewhere. This origin indices we've got one of those.
+    FreeRegion,
+
+    Inferred(::mir::visit::TyContext),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -1030,11 +1044,23 @@ pub fn next_float_var_id(&self) -> FloatVid {
             .new_key(None)
     }
 
+    /// Create a fresh region variable with the next available index.
+    ///
+    /// # Parameters
+    ///
+    /// - `origin`: information about why we created this variable, for use
+    ///   during diagnostics / error-reporting.
     pub fn next_region_var(&self, origin: RegionVariableOrigin)
                            -> ty::Region<'tcx> {
         self.tcx.mk_region(ty::ReVar(self.borrow_region_constraints().new_region_var(origin)))
     }
 
+    /// Just a convenient wrapper of `next_region_var` for using during NLL.
+    pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin)
+                               -> ty::Region<'tcx> {
+        self.next_region_var(RegionVariableOrigin::NLL(origin))
+    }
+
     /// Create a region inference variable for the given
     /// region parameter definition.
     pub fn region_var_for_def(&self,
@@ -1166,19 +1192,18 @@ pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
         self.borrow_region_constraints().take_and_reset_data()
     }
 
-    /// Returns the number of region variables created thus far.
-    pub fn num_region_vars(&self) -> usize {
-        self.borrow_region_constraints().var_origins().len()
-    }
-
-    /// Returns an iterator over all region variables created thus far.
-    pub fn all_region_vars(&self) -> impl Iterator<Item = RegionVid> {
-        self.borrow_region_constraints().var_origins().indices()
-    }
-
-    /// Returns the origin of a given region variable.
-    pub fn region_var_origin(&self, var: RegionVid) -> RegionVariableOrigin {
-        self.borrow_region_constraints().var_origins()[var].clone()
+    /// Takes ownership of the list of variable regions. This implies
+    /// that all the region constriants have already been taken, and
+    /// hence that `resolve_regions_and_report_errors` can never be
+    /// called. This is used only during NLL processing to "hand off" ownership
+    /// of the set of region vairables into the NLL region context.
+    pub fn take_region_var_origins(&self) -> VarOrigins {
+        let (var_origins, data) = self.region_constraints.borrow_mut()
+                                                         .take()
+                                                         .expect("regions already resolved")
+                                                         .into_origins_and_data();
+        assert!(data.is_empty());
+        var_origins
     }
 
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
@@ -1609,7 +1634,8 @@ pub fn span(&self) -> Span {
             EarlyBoundRegion(a, ..) => a,
             LateBoundRegion(a, ..) => a,
             BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
-            UpvarRegion(_, a) => a
+            UpvarRegion(_, a) => a,
+            NLL(..) => bug!("NLL variable used with `span`"),
         }
     }
 }
index 00863abc84deeb61b4e5652aadbdb399b34895fc..b75163dbaa60f78acfe017d34ec5c9d5b65392a7 100644 (file)
@@ -811,7 +811,7 @@ fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Locatio
 
 /// Extra information passed to `visit_ty` and friends to give context
 /// about where the type etc appears.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum TyContext {
     LocalDecl {
         /// The index of the local variable we are visiting.
index a0334ed078f44e8090ba35c186769ac5d235d7da..15c74f49c11610cc5597c98ac5fcb29b82761bd5 100644 (file)
@@ -64,7 +64,8 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
 
     // Create the region inference context, generate the constraints,
     // and then solve them.
-    let mut regioncx = RegionInferenceContext::new(infcx, free_regions, mir);
+    let var_origins = infcx.take_region_var_origins();
+    let mut regioncx = RegionInferenceContext::new(var_origins, free_regions, mir);
     let param_env = infcx.tcx.param_env(def_id);
     constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, param_env, liveness);
     regioncx.solve(infcx, &mir);
index f1160d42155ab56df83556f62823c042a9905f65..24821529bade0f983d153a2bbb0315eb969cf154 100644 (file)
@@ -10,6 +10,9 @@
 
 use super::free_regions::FreeRegions;
 use rustc::infer::InferCtxt;
+use rustc::infer::RegionVariableOrigin;
+use rustc::infer::NLLRegionVariableOrigin;
+use rustc::infer::region_constraints::VarOrigins;
 use rustc::mir::{Location, Mir};
 use rustc::ty::{self, RegionVid};
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -25,23 +28,17 @@ pub struct RegionInferenceContext<'tcx> {
     /// from as well as its final inferred value.
     definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
 
-    /// The indices of all "free regions" in scope. These are the
-    /// lifetime parameters (anonymous and named) declared in the
-    /// function signature:
-    ///
-    ///     fn foo<'a, 'b>(x: &Foo<'a, 'b>)
-    ///            ^^  ^^     ^
-    ///
-    /// These indices will be from 0..N, as it happens, but we collect
-    /// them into a vector for convenience.
-    free_regions: Vec<RegionVid>,
-
     /// The constraints we have accumulated and used during solving.
     constraints: Vec<Constraint>,
 }
 
-#[derive(Default)]
 struct RegionDefinition<'tcx> {
+    /// Why we created this variable. Mostly these will be
+    /// `RegionVariableOrigin::NLL`, but some variables get created
+    /// elsewhere in the code with other causes (e.g., instantiation
+    /// late-bound-regions).
+    origin: RegionVariableOrigin,
+
     /// If this is a free-region, then this is `Some(X)` where `X` is
     /// the name of the region.
     name: Option<ty::Region<'tcx>>,
@@ -112,15 +109,16 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
     /// `num_region_variables` valid inference variables; the first N
     /// of those will be constant regions representing the free
     /// regions defined in `free_regions`.
-    pub fn new(
-        infcx: &InferCtxt<'_, '_, 'tcx>,
-        free_regions: &FreeRegions<'tcx>,
-        mir: &Mir<'tcx>,
-    ) -> Self {
+    pub fn new(var_origins: VarOrigins, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) -> Self {
+        // Create a RegionDefinition for each inference variable.
+        let definitions = var_origins
+            .into_iter()
+            .map(|origin| RegionDefinition::new(origin))
+            .collect();
+
         let mut result = Self {
-            definitions: infcx.all_region_vars().map(|_| RegionDefinition::default()).collect(),
+            definitions: definitions,
             constraints: Vec::new(),
-            free_regions: Vec::new(),
         };
 
         result.init_free_regions(free_regions, mir);
@@ -155,7 +153,11 @@ fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx
 
         // For each free region X:
         for (free_region, &variable) in indices {
-            self.free_regions.push(variable);
+            // These should be free-region variables.
+            assert!(match self.definitions[variable].origin {
+                RegionVariableOrigin::NLL(NLLRegionVariableOrigin::FreeRegion) => true,
+                _ => false,
+            });
 
             // Initialize the name and a few other details.
             self.definitions[variable].name = Some(free_region);
@@ -262,10 +264,7 @@ pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
-    fn propagate_constraints(
-        &mut self,
-        mir: &Mir<'tcx>,
-    ) -> Vec<(RegionVid, Span, RegionVid)> {
+    fn propagate_constraints(&mut self, mir: &Mir<'tcx>) -> Vec<(RegionVid, Span, RegionVid)> {
         let mut changed = true;
         let mut dfs = Dfs::new(mir);
         let mut error_regions = FxHashSet();
@@ -393,3 +392,17 @@ fn copy(
         changed
     }
 }
+
+impl<'tcx> RegionDefinition<'tcx> {
+    fn new(origin: RegionVariableOrigin) -> Self {
+        // Create a new region definition. Note that, for free
+        // regions, these fields get updated later in
+        // `init_free_regions`.
+        Self {
+            origin,
+            name: None,
+            constant: false,
+            value: Region::default(),
+        }
+    }
+}
index c053dab123d7fff3fe23740d3d522be1470f666d..a7c8deb18544a48e0c70ce82aa16d43b4e31de4e 100644 (file)
@@ -9,14 +9,13 @@
 // except according to those terms.
 
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc::ty::subst::{Kind, Substs};
-use rustc::ty::{self, ClosureSubsts, RegionKind, RegionVid, Ty, TypeFoldable};
+use rustc::ty::subst::Substs;
+use rustc::ty::{self, ClosureSubsts, RegionVid, Ty, TypeFoldable};
 use rustc::mir::{BasicBlock, Local, Location, Mir, Rvalue, Statement, StatementKind};
 use rustc::mir::visit::{MutVisitor, TyContext};
-use rustc::infer::{self as rustc_infer, InferCtxt};
-use syntax_pos::DUMMY_SP;
-use std::collections::HashMap;
+use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
+use super::ToRegionVid;
 use super::free_regions::FreeRegions;
 
 /// Replaces all free regions appearing in the MIR with fresh
@@ -29,14 +28,16 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>(
     // Create inference variables for each of the free regions
     // declared on the function signature.
     let free_region_inference_vars = (0..free_regions.indices.len())
-        .map(|_| {
-            infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP))
+        .map(RegionVid::new)
+        .map(|vid_expected| {
+            let r = infcx.next_nll_region_var(NLLRegionVariableOrigin::FreeRegion);
+            assert_eq!(vid_expected, r.to_region_vid());
+            r
         })
         .collect();
 
     let mut visitor = NLLVisitor {
         infcx,
-        lookup_map: HashMap::new(),
         free_regions,
         free_region_inference_vars,
         arg_count: mir.arg_count,
@@ -45,7 +46,6 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>(
 }
 
 struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    lookup_map: HashMap<RegionVid, TyContext>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     free_regions: &'a FreeRegions<'tcx>,
     free_region_inference_vars: IndexVec<RegionVid, ty::Region<'tcx>>,
@@ -56,14 +56,15 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
     /// Replaces all regions appearing in `value` with fresh inference
     /// variables. This is what we do for almost the entire MIR, with
     /// the exception of the declared types of our arguments.
-    fn renumber_regions<T>(&mut self, value: &T) -> T
+    fn renumber_regions<T>(&mut self, ty_context: TyContext, value: &T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
         self.infcx
             .tcx
             .fold_regions(value, &mut false, |_region, _depth| {
-                self.infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP))
+                let origin = NLLRegionVariableOrigin::Inferred(ty_context);
+                self.infcx.next_nll_region_var(origin)
             })
     }
 
@@ -81,26 +82,6 @@ fn renumber_free_regions<T>(&mut self, value: &T) -> T
             })
     }
 
-    fn store_region(&mut self, region: &RegionKind, lookup: TyContext) {
-        if let RegionKind::ReVar(rid) = *region {
-            self.lookup_map.entry(rid).or_insert(lookup);
-        }
-    }
-
-    fn store_ty_regions(&mut self, ty: &Ty<'tcx>, ty_context: TyContext) {
-        for region in ty.regions() {
-            self.store_region(region, ty_context);
-        }
-    }
-
-    fn store_kind_regions(&mut self, kind: &'tcx Kind, ty_context: TyContext) {
-        if let Some(ty) = kind.as_type() {
-            self.store_ty_regions(&ty, ty_context);
-        } else if let Some(region) = kind.as_region() {
-            self.store_region(region, ty_context);
-        }
-    }
-
     fn is_argument_or_return_slot(&self, local: Local) -> bool {
         // The first argument is return slot, next N are arguments.
         local.index() <= self.arg_count
@@ -118,26 +99,21 @@ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
         *ty = if is_arg {
             self.renumber_free_regions(&old_ty)
         } else {
-            self.renumber_regions(&old_ty)
+            self.renumber_regions(ty_context, &old_ty)
         };
-        self.store_ty_regions(ty, ty_context);
     }
 
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
-        *substs = self.renumber_regions(&{ *substs });
         let ty_context = TyContext::Location(location);
-        for kind in *substs {
-            self.store_kind_regions(kind, ty_context);
-        }
+        *substs = self.renumber_regions(ty_context, &{ *substs });
     }
 
     fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
         match *rvalue {
             Rvalue::Ref(ref mut r, _, _) => {
                 let old_r = *r;
-                *r = self.renumber_regions(&old_r);
                 let ty_context = TyContext::Location(location);
-                self.store_region(r, ty_context);
+                *r = self.renumber_regions(ty_context, &old_r);
             }
             Rvalue::Use(..) |
             Rvalue::Repeat(..) |
@@ -156,11 +132,8 @@ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
     }
 
     fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: Location) {
-        *substs = self.renumber_regions(substs);
         let ty_context = TyContext::Location(location);
-        for kind in substs.substs {
-            self.store_kind_regions(kind, ty_context);
-        }
+        *substs = self.renumber_regions(ty_context, substs);
     }
 
     fn visit_statement(
index a3dbcefd0e0caf1572c175f82e685216bd43e7f7..837c3d42fe83701e5ee84e021af4e1c402dc6280 100644 (file)
@@ -11,8 +11,8 @@
 //! This pass type-checks the MIR to ensure it is not broken.
 #![allow(unreachable_code)]
 
-use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime,
-                   RegionConstraintData, UnitResult};
+use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
+use rustc::infer::region_constraints::RegionConstraintData;
 use rustc::traits::{self, FulfillmentContext};
 use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;