Skip to content

Commit 2f052eb

Browse files
author
Ariel Ben-Yehuda
committed
use the parameter environment when checking dtors
This makes it more uniform. No functional changes.
1 parent 5c630a6 commit 2f052eb

File tree

7 files changed

+98
-121
lines changed

7 files changed

+98
-121
lines changed

src/librustc/middle/infer/higher_ranked/mod.rs

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
1515
use super::combine::CombineFields;
1616

17-
use middle::subst;
1817
use middle::ty::{self, TypeError, Binder};
1918
use middle::ty_fold::{self, TypeFoldable};
2019
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
@@ -455,63 +454,6 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
455454
}
456455
}
457456

458-
/// Constructs and returns a substitution that, for a given type
459-
/// scheme parameterized by `generics`, will replace every generic
460-
/// parameter in the type with a skolemized type/region (which one can
461-
/// think of as a "fresh constant", except at the type/region level of
462-
/// reasoning).
463-
///
464-
/// Since we currently represent bound/free type parameters in the
465-
/// same way, this only has an effect on regions.
466-
///
467-
/// (Note that unlike a substitution from `ty::construct_free_substs`,
468-
/// this inserts skolemized regions rather than free regions; this
469-
/// allows one to use `fn leak_check` to catch attmepts to unify the
470-
/// skolemized regions with e.g. the `'static` lifetime)
471-
pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
472-
generics: &ty::Generics<'tcx>,
473-
snapshot: &CombinedSnapshot)
474-
-> (subst::Substs<'tcx>, SkolemizationMap)
475-
{
476-
let mut map = FnvHashMap();
477-
478-
// map T => T
479-
let mut types = subst::VecPerParamSpace::empty();
480-
push_types_from_defs(infcx.tcx, &mut types, generics.types.as_slice());
481-
482-
// map early- or late-bound 'a => fresh 'a
483-
let mut regions = subst::VecPerParamSpace::empty();
484-
push_region_params(infcx, &mut map, &mut regions, generics.regions.as_slice(), snapshot);
485-
486-
let substs = subst::Substs { types: types,
487-
regions: subst::NonerasedRegions(regions) };
488-
return (substs, map);
489-
490-
fn push_region_params<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
491-
map: &mut SkolemizationMap,
492-
regions: &mut subst::VecPerParamSpace<ty::Region>,
493-
region_params: &[ty::RegionParameterDef],
494-
snapshot: &CombinedSnapshot)
495-
{
496-
for r in region_params {
497-
let br = r.to_bound_region();
498-
let skol_var = infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot);
499-
let sanity_check = map.insert(br, skol_var);
500-
assert!(sanity_check.is_none());
501-
regions.push(r.space, skol_var);
502-
}
503-
}
504-
505-
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
506-
types: &mut subst::VecPerParamSpace<ty::Ty<'tcx>>,
507-
defs: &[ty::TypeParameterDef<'tcx>]) {
508-
for def in defs {
509-
let ty = tcx.mk_param_from_def(def);
510-
types.push(def.space, ty);
511-
}
512-
}
513-
}
514-
515457
pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
516458
binder: &ty::Binder<T>,
517459
snapshot: &CombinedSnapshot)

src/librustc/middle/infer/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -948,15 +948,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
948948
})
949949
}
950950

951-
pub fn construct_skolemized_subst(&self,
952-
generics: &ty::Generics<'tcx>,
953-
snapshot: &CombinedSnapshot)
954-
-> (subst::Substs<'tcx>, SkolemizationMap) {
955-
/*! See `higher_ranked::construct_skolemized_subst` */
956-
957-
higher_ranked::construct_skolemized_substs(self, generics, snapshot)
958-
}
959-
960951
pub fn skolemize_late_bound_regions<T>(&self,
961952
value: &ty::Binder<T>,
962953
snapshot: &CombinedSnapshot)

src/librustc/middle/infer/region_inference/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
373373

374374
let sc = self.skolemization_count.get();
375375
self.skolemization_count.set(sc + 1);
376-
ReSkolemized(sc, br)
376+
ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)
377377
}
378378

379379
pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {

src/librustc/middle/ty.rs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,62 @@ pub struct DebruijnIndex {
15021502
pub depth: u32,
15031503
}
15041504

1505-
/// Representation of regions:
1505+
/// Representation of regions.
1506+
///
1507+
/// Unlike types, most region variants are "fictitious", not concrete,
1508+
/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
1509+
/// ones representing concrete regions.
1510+
///
1511+
/// ## Bound Regions
1512+
///
1513+
/// These are regions that are stored behind a binder and must be substituted
1514+
/// with some concrete region before being used. There are 2 kind of
1515+
/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
1516+
/// and are substituted by a Substs, and late-bound, which are part of
1517+
/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
1518+
/// the likes of `liberate_late_bound_regions`. The distinction exists
1519+
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
1520+
///
1521+
/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
1522+
/// outside their binder, e.g. in types passed to type inference, and
1523+
/// should first be substituted (by skolemized regions, free regions,
1524+
/// or region variables).
1525+
///
1526+
/// ## Skolemized and Free Regions
1527+
///
1528+
/// One often wants to work with bound regions without knowing their precise
1529+
/// identity. For example, when checking a function, the lifetime of a borrow
1530+
/// can end up being assigned to some region parameter. In these cases,
1531+
/// it must be ensured that bounds on the region can't be accidentally
1532+
/// assumed without being checked.
1533+
///
1534+
/// The process of doing that is called "skolemization". The bound regions
1535+
/// are replaced by skolemized markers, which don't satisfy any relation
1536+
/// not explicity provided.
1537+
///
1538+
/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
1539+
/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
1540+
/// to be used. These also support explicit bounds: both the internally-stored
1541+
/// *scope*, which the region is assumed to outlive, as well as other
1542+
/// relations stored in the `FreeRegionMap`. Note that these relations
1543+
/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
1544+
/// `resolve_regions_and_report_errors`.
1545+
///
1546+
/// When working with higher-ranked types, some region relations aren't
1547+
/// yet known, so you can't just call `resolve_regions_and_report_errors`.
1548+
/// `ReSkolemized` is designed for this purpose. In these contexts,
1549+
/// there's also the risk that some inference variable laying around will
1550+
/// get unified with your skolemized region: if you want to check whether
1551+
/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
1552+
/// with a skolemized region `'%a`, the variable `'_` would just be
1553+
/// instantiated to the skolemized region `'%a`, which is wrong because
1554+
/// the inference variable is supposed to satisfy the relation
1555+
/// *for every value of the skolemized region*. To ensure that doesn't
1556+
/// happen, you can use `leak_check`. This is more clearly explained
1557+
/// by infer/higher_ranked/README.md.
1558+
///
1559+
/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
1560+
/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
15061561
#[derive(Clone, PartialEq, Eq, Hash, Copy)]
15071562
pub enum Region {
15081563
// Region bound in a type or fn declaration which will be
@@ -1532,7 +1587,7 @@ pub enum Region {
15321587

15331588
/// A skolemized region - basically the higher-ranked version of ReFree.
15341589
/// Should not exist after typeck.
1535-
ReSkolemized(u32, BoundRegion),
1590+
ReSkolemized(SkolemizedRegionVid, BoundRegion),
15361591

15371592
/// Empty lifetime is for data that is never accessed.
15381593
/// Bottom in the region lattice. We treat ReEmpty somewhat
@@ -2168,6 +2223,11 @@ pub struct RegionVid {
21682223
pub index: u32
21692224
}
21702225

2226+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2227+
pub struct SkolemizedRegionVid {
2228+
pub index: u32
2229+
}
2230+
21712231
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
21722232
pub enum InferTy {
21732233
TyVar(TyVid),

src/librustc/util/ppaux.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ impl fmt::Debug for ty::Region {
418418
}
419419

420420
ty::ReSkolemized(id, ref bound_region) => {
421-
write!(f, "ReSkolemized({}, {:?})", id, bound_region)
421+
write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
422422
}
423423

424424
ty::ReEmpty => write!(f, "ReEmpty")

src/librustc_typeck/check/dropck.rs

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
use check::regionck::{self, Rcx};
1212

1313
use middle::def_id::{DefId, LOCAL_CRATE};
14+
use middle::free_region::FreeRegionMap;
1415
use middle::infer;
1516
use middle::region;
1617
use middle::subst::{self, Subst};
18+
use middle::traits;
1719
use middle::ty::{self, Ty};
1820
use util::nodemap::FnvHashSet;
1921

@@ -75,61 +77,41 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
7577
drop_impl_ty: &ty::Ty<'tcx>,
7678
self_type_did: DefId) -> Result<(), ()>
7779
{
78-
// New strategy based on review suggestion from nikomatsakis.
79-
//
80-
// (In the text and code below, "named" denotes "struct/enum", and
81-
// "generic params" denotes "type and region params")
82-
//
83-
// 1. Create fresh skolemized type/region "constants" for each of
84-
// the named type's generic params. Instantiate the named type
85-
// with the fresh constants, yielding `named_skolem`.
86-
//
87-
// 2. Create unification variables for each of the Drop impl's
88-
// generic params. Instantiate the impl's Self's type with the
89-
// unification-vars, yielding `drop_unifier`.
90-
//
91-
// 3. Attempt to unify Self_unif with Type_skolem. If unification
92-
// succeeds, continue (i.e. with the predicate checks).
93-
94-
let ty::TypeScheme { generics: ref named_type_generics,
95-
ty: named_type } =
96-
tcx.lookup_item_type(self_type_did);
97-
98-
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
99-
100-
infcx.commit_if_ok(|snapshot| {
101-
let (named_type_to_skolem, skol_map) =
102-
infcx.construct_skolemized_subst(named_type_generics, snapshot);
103-
let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
104-
105-
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
106-
let drop_to_unifier =
107-
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
108-
let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier);
109-
110-
if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
111-
named_type_skolem, drop_unifier) {
112-
// Even if we did manage to equate the types, the process
113-
// may have just gathered unsolvable region constraints
114-
// like `R == 'static` (represented as a pair of subregion
115-
// constraints) for some skolemization constant R.
116-
//
117-
// However, the leak_check method allows us to confirm
118-
// that no skolemized regions escaped (i.e. were related
119-
// to other regions in the constraint graph).
120-
if let Ok(()) = infcx.leak_check(&skol_map, snapshot) {
121-
return Ok(())
122-
}
123-
}
80+
assert!(drop_impl_did.is_local() && self_type_did.is_local());
81+
82+
// check that the impl type can be made to match the trait type.
83+
84+
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_did.node);
85+
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true);
86+
87+
let named_type = tcx.lookup_item_type(self_type_did).ty;
88+
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
12489

90+
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
91+
let fresh_impl_substs =
92+
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
93+
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
94+
95+
if let Err(_) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
96+
named_type, fresh_impl_self_ty) {
12597
span_err!(tcx.sess, drop_impl_span, E0366,
12698
"Implementations of Drop cannot be specialized");
12799
let item_span = tcx.map.span(self_type_did.node);
128100
tcx.sess.span_note(item_span,
129101
"Use same sequence of generic type and region \
130102
parameters that is on the struct/enum definition");
131103
return Err(());
132-
})
104+
}
105+
106+
if let Err(ref errors) = infcx.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
107+
// this could be reached when we get lazy normalization
108+
traits::report_fulfillment_errors(&infcx, errors);
109+
return Err(());
110+
}
111+
112+
let free_regions = FreeRegionMap::new();
113+
infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_did.node);
114+
Ok(())
133115
}
134116

135117
/// Confirms that every predicate imposed by dtor_predicates is

src/test/compile-fail/reject-specialized-drops-8142.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // RE
3737
impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT
3838

3939
impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
40-
//~^ ERROR Implementations of Drop cannot be specialized
40+
//~^ ERROR mismatched types
41+
//~| expected `N<'n>`
42+
//~| found `N<'static>`
4143

4244
impl<Cok_nobound> Drop for O<Cok_nobound> { fn drop(&mut self) { } } // ACCEPT
4345

@@ -57,9 +59,9 @@ impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT
5759
impl Drop for U { fn drop(&mut self) { } } // ACCEPT
5860

5961
impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
60-
//~^ERROR Implementations of Drop cannot be specialized
62+
//~^ ERROR Implementations of Drop cannot be specialized
6163

6264
impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
63-
//~^ERROR Implementations of Drop cannot be specialized
65+
//~^ ERROR cannot infer an appropriate lifetime
6466

6567
pub fn main() { }

0 commit comments

Comments
 (0)