formalize giving ownership of region vars to region inf. context
This commit is contained in:
parent
109c9a79ed
commit
51ce1f9493
@ -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,
|
||||
|
@ -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<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 @@ 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`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 @@ 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ 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(
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user