diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 67fdd68a826..84baece77fe 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1029,6 +1029,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 10734802a6d..2b080c54da1 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -16,7 +16,6 @@ pub use self::SubregionOrigin::*; 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 middle::lang_items; 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 arena::DroplessArena; 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 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .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 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, '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 { - 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 @@ impl RegionVariableOrigin { EarlyBoundRegion(a, ..) => a, LateBoundRegion(a, ..) => a, BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP, - UpvarRegion(_, a) => a + UpvarRegion(_, a) => a, + NLL(..) => bug!("NLL variable used with `span`"), } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 00863abc84d..b75163dbaa6 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -811,7 +811,7 @@ make_mir_visitor!(MutVisitor,mut); /// 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. diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs index a0334ed078f..15c74f49c11 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/transform/nll/mod.rs @@ -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); diff --git a/src/librustc_mir/transform/nll/region_infer.rs b/src/librustc_mir/transform/nll/region_infer.rs index f1160d42155..24821529bad 100644 --- a/src/librustc_mir/transform/nll/region_infer.rs +++ b/src/librustc_mir/transform/nll/region_infer.rs @@ -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>, - /// 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, - /// The constraints we have accumulated and used during solving. constraints: Vec, } -#[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>, @@ -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 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'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 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'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 @@ impl<'a, 'tcx> Dfs<'a, 'tcx> { 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(), + } + } +} diff --git a/src/librustc_mir/transform/nll/renumber.rs b/src/librustc_mir/transform/nll/renumber.rs index c053dab123d..a7c8deb1854 100644 --- a/src/librustc_mir/transform/nll/renumber.rs +++ b/src/librustc_mir/transform/nll/renumber.rs @@ -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, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, free_regions: &'a FreeRegions<'tcx>, free_region_inference_vars: IndexVec>, @@ -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(&mut self, value: &T) -> T + fn renumber_regions(&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 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { }) } - 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 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { *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 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { } 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( diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index a3dbcefd0e0..837c3d42fe8 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -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;