use the parameter environment when checking dtors
This makes it more uniform. No functional changes.
This commit is contained in:
parent
5c630a61c6
commit
2f052eb0b1
7 changed files with 94 additions and 117 deletions
|
@ -14,7 +14,6 @@
|
|||
use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
|
||||
use super::combine::CombineFields;
|
||||
|
||||
use middle::subst;
|
||||
use middle::ty::{self, TypeError, Binder};
|
||||
use middle::ty_fold::{self, TypeFoldable};
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
|
@ -455,63 +454,6 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Constructs and returns a substitution that, for a given type
|
||||
/// scheme parameterized by `generics`, will replace every generic
|
||||
/// parameter in the type with a skolemized type/region (which one can
|
||||
/// think of as a "fresh constant", except at the type/region level of
|
||||
/// reasoning).
|
||||
///
|
||||
/// Since we currently represent bound/free type parameters in the
|
||||
/// same way, this only has an effect on regions.
|
||||
///
|
||||
/// (Note that unlike a substitution from `ty::construct_free_substs`,
|
||||
/// this inserts skolemized regions rather than free regions; this
|
||||
/// allows one to use `fn leak_check` to catch attmepts to unify the
|
||||
/// skolemized regions with e.g. the `'static` lifetime)
|
||||
pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> (subst::Substs<'tcx>, SkolemizationMap)
|
||||
{
|
||||
let mut map = FnvHashMap();
|
||||
|
||||
// map T => T
|
||||
let mut types = subst::VecPerParamSpace::empty();
|
||||
push_types_from_defs(infcx.tcx, &mut types, generics.types.as_slice());
|
||||
|
||||
// map early- or late-bound 'a => fresh 'a
|
||||
let mut regions = subst::VecPerParamSpace::empty();
|
||||
push_region_params(infcx, &mut map, &mut regions, generics.regions.as_slice(), snapshot);
|
||||
|
||||
let substs = subst::Substs { types: types,
|
||||
regions: subst::NonerasedRegions(regions) };
|
||||
return (substs, map);
|
||||
|
||||
fn push_region_params<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
map: &mut SkolemizationMap,
|
||||
regions: &mut subst::VecPerParamSpace<ty::Region>,
|
||||
region_params: &[ty::RegionParameterDef],
|
||||
snapshot: &CombinedSnapshot)
|
||||
{
|
||||
for r in region_params {
|
||||
let br = r.to_bound_region();
|
||||
let skol_var = infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot);
|
||||
let sanity_check = map.insert(br, skol_var);
|
||||
assert!(sanity_check.is_none());
|
||||
regions.push(r.space, skol_var);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
types: &mut subst::VecPerParamSpace<ty::Ty<'tcx>>,
|
||||
defs: &[ty::TypeParameterDef<'tcx>]) {
|
||||
for def in defs {
|
||||
let ty = tcx.mk_param_from_def(def);
|
||||
types.push(def.space, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
binder: &ty::Binder<T>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
|
|
|
@ -948,15 +948,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn construct_skolemized_subst(&self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> (subst::Substs<'tcx>, SkolemizationMap) {
|
||||
/*! See `higher_ranked::construct_skolemized_subst` */
|
||||
|
||||
higher_ranked::construct_skolemized_substs(self, generics, snapshot)
|
||||
}
|
||||
|
||||
pub fn skolemize_late_bound_regions<T>(&self,
|
||||
value: &ty::Binder<T>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
|
|
|
@ -373,7 +373,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
|
||||
let sc = self.skolemization_count.get();
|
||||
self.skolemization_count.set(sc + 1);
|
||||
ReSkolemized(sc, br)
|
||||
ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)
|
||||
}
|
||||
|
||||
pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
|
||||
|
|
|
@ -1502,7 +1502,62 @@ pub struct DebruijnIndex {
|
|||
pub depth: u32,
|
||||
}
|
||||
|
||||
/// Representation of regions:
|
||||
/// Representation of regions.
|
||||
///
|
||||
/// Unlike types, most region variants are "fictitious", not concrete,
|
||||
/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
|
||||
/// ones representing concrete regions.
|
||||
///
|
||||
/// ## Bound Regions
|
||||
///
|
||||
/// These are regions that are stored behind a binder and must be substituted
|
||||
/// with some concrete region before being used. There are 2 kind of
|
||||
/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
|
||||
/// and are substituted by a Substs, and late-bound, which are part of
|
||||
/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
|
||||
/// the likes of `liberate_late_bound_regions`. The distinction exists
|
||||
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
|
||||
///
|
||||
/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
|
||||
/// outside their binder, e.g. in types passed to type inference, and
|
||||
/// should first be substituted (by skolemized regions, free regions,
|
||||
/// or region variables).
|
||||
///
|
||||
/// ## Skolemized and Free Regions
|
||||
///
|
||||
/// One often wants to work with bound regions without knowing their precise
|
||||
/// identity. For example, when checking a function, the lifetime of a borrow
|
||||
/// can end up being assigned to some region parameter. In these cases,
|
||||
/// it must be ensured that bounds on the region can't be accidentally
|
||||
/// assumed without being checked.
|
||||
///
|
||||
/// The process of doing that is called "skolemization". The bound regions
|
||||
/// are replaced by skolemized markers, which don't satisfy any relation
|
||||
/// not explicity provided.
|
||||
///
|
||||
/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
|
||||
/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
|
||||
/// to be used. These also support explicit bounds: both the internally-stored
|
||||
/// *scope*, which the region is assumed to outlive, as well as other
|
||||
/// relations stored in the `FreeRegionMap`. Note that these relations
|
||||
/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
|
||||
/// `resolve_regions_and_report_errors`.
|
||||
///
|
||||
/// When working with higher-ranked types, some region relations aren't
|
||||
/// yet known, so you can't just call `resolve_regions_and_report_errors`.
|
||||
/// `ReSkolemized` is designed for this purpose. In these contexts,
|
||||
/// there's also the risk that some inference variable laying around will
|
||||
/// get unified with your skolemized region: if you want to check whether
|
||||
/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
|
||||
/// with a skolemized region `'%a`, the variable `'_` would just be
|
||||
/// instantiated to the skolemized region `'%a`, which is wrong because
|
||||
/// the inference variable is supposed to satisfy the relation
|
||||
/// *for every value of the skolemized region*. To ensure that doesn't
|
||||
/// happen, you can use `leak_check`. This is more clearly explained
|
||||
/// by infer/higher_ranked/README.md.
|
||||
///
|
||||
/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
|
||||
/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Copy)]
|
||||
pub enum Region {
|
||||
// Region bound in a type or fn declaration which will be
|
||||
|
@ -1532,7 +1587,7 @@ pub enum Region {
|
|||
|
||||
/// A skolemized region - basically the higher-ranked version of ReFree.
|
||||
/// Should not exist after typeck.
|
||||
ReSkolemized(u32, BoundRegion),
|
||||
ReSkolemized(SkolemizedRegionVid, BoundRegion),
|
||||
|
||||
/// Empty lifetime is for data that is never accessed.
|
||||
/// Bottom in the region lattice. We treat ReEmpty somewhat
|
||||
|
@ -2168,6 +2223,11 @@ pub struct RegionVid {
|
|||
pub index: u32
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct SkolemizedRegionVid {
|
||||
pub index: u32
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum InferTy {
|
||||
TyVar(TyVid),
|
||||
|
|
|
@ -418,7 +418,7 @@ impl fmt::Debug for ty::Region {
|
|||
}
|
||||
|
||||
ty::ReSkolemized(id, ref bound_region) => {
|
||||
write!(f, "ReSkolemized({}, {:?})", id, bound_region)
|
||||
write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
|
||||
}
|
||||
|
||||
ty::ReEmpty => write!(f, "ReEmpty")
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
use check::regionck::{self, Rcx};
|
||||
|
||||
use middle::def_id::{DefId, LOCAL_CRATE};
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use middle::infer;
|
||||
use middle::region;
|
||||
use middle::subst::{self, Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::{self, Ty};
|
||||
use util::nodemap::FnvHashSet;
|
||||
|
||||
|
@ -75,53 +77,23 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
|||
drop_impl_ty: &ty::Ty<'tcx>,
|
||||
self_type_did: DefId) -> Result<(), ()>
|
||||
{
|
||||
// New strategy based on review suggestion from nikomatsakis.
|
||||
//
|
||||
// (In the text and code below, "named" denotes "struct/enum", and
|
||||
// "generic params" denotes "type and region params")
|
||||
//
|
||||
// 1. Create fresh skolemized type/region "constants" for each of
|
||||
// the named type's generic params. Instantiate the named type
|
||||
// with the fresh constants, yielding `named_skolem`.
|
||||
//
|
||||
// 2. Create unification variables for each of the Drop impl's
|
||||
// generic params. Instantiate the impl's Self's type with the
|
||||
// unification-vars, yielding `drop_unifier`.
|
||||
//
|
||||
// 3. Attempt to unify Self_unif with Type_skolem. If unification
|
||||
// succeeds, continue (i.e. with the predicate checks).
|
||||
assert!(drop_impl_did.is_local() && self_type_did.is_local());
|
||||
|
||||
let ty::TypeScheme { generics: ref named_type_generics,
|
||||
ty: named_type } =
|
||||
tcx.lookup_item_type(self_type_did);
|
||||
// check that the impl type can be made to match the trait type.
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
|
||||
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_did.node);
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true);
|
||||
|
||||
infcx.commit_if_ok(|snapshot| {
|
||||
let (named_type_to_skolem, skol_map) =
|
||||
infcx.construct_skolemized_subst(named_type_generics, snapshot);
|
||||
let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
|
||||
let named_type = tcx.lookup_item_type(self_type_did).ty;
|
||||
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
|
||||
|
||||
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
|
||||
let drop_to_unifier =
|
||||
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
|
||||
let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier);
|
||||
|
||||
if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
|
||||
named_type_skolem, drop_unifier) {
|
||||
// Even if we did manage to equate the types, the process
|
||||
// may have just gathered unsolvable region constraints
|
||||
// like `R == 'static` (represented as a pair of subregion
|
||||
// constraints) for some skolemization constant R.
|
||||
//
|
||||
// However, the leak_check method allows us to confirm
|
||||
// that no skolemized regions escaped (i.e. were related
|
||||
// to other regions in the constraint graph).
|
||||
if let Ok(()) = infcx.leak_check(&skol_map, snapshot) {
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
|
||||
let fresh_impl_substs =
|
||||
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
|
||||
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
|
||||
|
||||
if let Err(_) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
|
||||
named_type, fresh_impl_self_ty) {
|
||||
span_err!(tcx.sess, drop_impl_span, E0366,
|
||||
"Implementations of Drop cannot be specialized");
|
||||
let item_span = tcx.map.span(self_type_did.node);
|
||||
|
@ -129,7 +101,17 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
|||
"Use same sequence of generic type and region \
|
||||
parameters that is on the struct/enum definition");
|
||||
return Err(());
|
||||
})
|
||||
}
|
||||
|
||||
if let Err(ref errors) = infcx.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
// this could be reached when we get lazy normalization
|
||||
traits::report_fulfillment_errors(&infcx, errors);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let free_regions = FreeRegionMap::new();
|
||||
infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_did.node);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Confirms that every predicate imposed by dtor_predicates is
|
||||
|
|
|
@ -37,7 +37,9 @@ impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // RE
|
|||
impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT
|
||||
|
||||
impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR Implementations of Drop cannot be specialized
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `N<'n>`
|
||||
//~| found `N<'static>`
|
||||
|
||||
impl<Cok_nobound> Drop for O<Cok_nobound> { fn drop(&mut self) { } } // ACCEPT
|
||||
|
||||
|
@ -57,9 +59,9 @@ impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT
|
|||
impl Drop for U { fn drop(&mut self) { } } // ACCEPT
|
||||
|
||||
impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ERROR Implementations of Drop cannot be specialized
|
||||
//~^ ERROR Implementations of Drop cannot be specialized
|
||||
|
||||
impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ERROR Implementations of Drop cannot be specialized
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
|
||||
pub fn main() { }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue