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,
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};
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;
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;
/// 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
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)]
.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,
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 {
EarlyBoundRegion(a, ..) => a,
LateBoundRegion(a, ..) => a,
BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
- UpvarRegion(_, a) => a
+ UpvarRegion(_, a) => a,
+ NLL(..) => bug!("NLL variable used with `span`"),
}
}
}
/// 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.
// 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);
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;
/// 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>>,
/// `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);
// 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);
/// 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();
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(),
+ }
+ }
+}
// 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
// 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,
}
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>>,
/// 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)
})
}
})
}
- 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
*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(..) |
}
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(
//! 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;