Unify the upvar variables found in closures with the actual types of the
upvars after analysis is done. Remove the `closure_upvars` helper and just consult this list of type variables directly.
This commit is contained in:
parent
a551697134
commit
7ba288dced
12 changed files with 214 additions and 252 deletions
|
@ -40,7 +40,6 @@ impl FreeRegionMap {
|
||||||
self.relate_free_regions(free_a, free_b);
|
self.relate_free_regions(free_a, free_b);
|
||||||
}
|
}
|
||||||
Implication::RegionSubRegion(..) |
|
Implication::RegionSubRegion(..) |
|
||||||
Implication::RegionSubClosure(..) |
|
|
||||||
Implication::RegionSubGeneric(..) |
|
Implication::RegionSubGeneric(..) |
|
||||||
Implication::Predicate(..) => {
|
Implication::Predicate(..) => {
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ use util::nodemap::FnvHashSet;
|
||||||
pub enum Implication<'tcx> {
|
pub enum Implication<'tcx> {
|
||||||
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
|
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
|
||||||
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
|
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
|
||||||
RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx ty::ClosureSubsts<'tcx>),
|
|
||||||
Predicate(ast::DefId, ty::Predicate<'tcx>),
|
Predicate(ast::DefId, ty::Predicate<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,10 +95,47 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
|
||||||
// No borrowed content reachable here.
|
// No borrowed content reachable here.
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyClosure(def_id, ref substs) => {
|
ty::TyClosure(_, ref substs) => {
|
||||||
// TODO remove RegionSubClosure
|
// FIXME(#27086). We do not accumulate from substs, since they
|
||||||
let &(r_a, opt_ty) = self.stack.last().unwrap();
|
// don't represent reachable data. This means that, in
|
||||||
self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
|
// practice, some of the lifetime parameters might not
|
||||||
|
// be in scope when the body runs, so long as there is
|
||||||
|
// no reachable data with that lifetime. For better or
|
||||||
|
// worse, this is consistent with fn types, however,
|
||||||
|
// which can also encapsulate data in this fashion
|
||||||
|
// (though it's somewhat harder, and typically
|
||||||
|
// requires virtual dispatch).
|
||||||
|
//
|
||||||
|
// Note that changing this (in a naive way, at least)
|
||||||
|
// causes regressions for what appears to be perfectly
|
||||||
|
// reasonable code like this:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// fn foo<'a>(p: &Data<'a>) {
|
||||||
|
// bar(|q: &mut Parser| q.read_addr())
|
||||||
|
// }
|
||||||
|
// fn bar(p: Box<FnMut(&mut Parser)+'static>) {
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Note that `p` (and `'a`) are not used in the
|
||||||
|
// closure at all, but to meet the requirement that
|
||||||
|
// the closure type `C: 'static` (so it can be coerce
|
||||||
|
// to the object type), we get the requirement that
|
||||||
|
// `'a: 'static` since `'a` appears in the closure
|
||||||
|
// type `C`.
|
||||||
|
//
|
||||||
|
// A smarter fix might "prune" unused `func_substs` --
|
||||||
|
// this would avoid breaking simple examples like
|
||||||
|
// this, but would still break others (which might
|
||||||
|
// indeed be invalid, depending on your POV). Pruning
|
||||||
|
// would be a subtle process, since we have to see
|
||||||
|
// what func/type parameters are used and unused,
|
||||||
|
// taking into consideration UFCS and so forth.
|
||||||
|
|
||||||
|
for &upvar_ty in &substs.upvar_tys {
|
||||||
|
self.accumulate_from_ty(upvar_ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyTrait(ref t) => {
|
ty::TyTrait(ref t) => {
|
||||||
|
@ -274,6 +310,21 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
|
||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
|
|
||||||
let variances = self.tcx().item_variances(def_id);
|
let variances = self.tcx().item_variances(def_id);
|
||||||
|
self.accumulate_from_substs(substs, Some(&variances));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accumulate_from_substs(&mut self,
|
||||||
|
substs: &Substs<'tcx>,
|
||||||
|
variances: Option<&ty::ItemVariances>)
|
||||||
|
{
|
||||||
|
let mut tmp_variances = None;
|
||||||
|
let variances = variances.unwrap_or_else(|| {
|
||||||
|
tmp_variances = Some(ty::ItemVariances {
|
||||||
|
types: substs.types.map(|_| ty::Variance::Invariant),
|
||||||
|
regions: substs.regions().map(|_| ty::Variance::Invariant),
|
||||||
|
});
|
||||||
|
tmp_variances.as_ref().unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) {
|
for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) {
|
||||||
match variance {
|
match variance {
|
||||||
|
|
|
@ -1399,20 +1399,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
closure_ty
|
closure_ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn closure_upvars(&self,
|
|
||||||
def_id: ast::DefId,
|
|
||||||
substs: &ty::ClosureSubsts<'tcx>)
|
|
||||||
-> Option<Vec<ty::ClosureUpvar<'tcx>>>
|
|
||||||
{
|
|
||||||
let result = ty::ctxt::closure_upvars(self, def_id, substs);
|
|
||||||
|
|
||||||
if self.normalize {
|
|
||||||
normalize_associated_type(&self.tcx, &result)
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeTrace<'tcx> {
|
impl<'tcx> TypeTrace<'tcx> {
|
||||||
|
|
|
@ -1284,22 +1284,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
candidates.ambiguous = true;
|
candidates.ambiguous = true;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if self.constituent_types_for_ty(self_ty).is_some() {
|
candidates.vec.push(DefaultImplCandidate(def_id.clone()))
|
||||||
candidates.vec.push(DefaultImplCandidate(def_id.clone()))
|
|
||||||
} else {
|
|
||||||
// We don't yet know what the constituent
|
|
||||||
// types are. So call it ambiguous for now,
|
|
||||||
// though this is a bit stronger than
|
|
||||||
// necessary: that is, we know that the
|
|
||||||
// defaulted impl applies, but we can't
|
|
||||||
// process the confirmation step without
|
|
||||||
// knowing the constituent types. (Anyway, in
|
|
||||||
// the particular case of defaulted impls, it
|
|
||||||
// doesn't really matter much either way,
|
|
||||||
// since we won't be aiding inference by
|
|
||||||
// processing the confirmation step.)
|
|
||||||
candidates.ambiguous = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1729,14 +1714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
return ok_if(Vec::new());
|
return ok_if(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
ok_if(substs.upvar_tys.clone())
|
||||||
match self.infcx.closure_upvars(def_id, substs) {
|
|
||||||
Some(upvars) => ok_if(upvars.iter().map(|c| c.ty).collect()),
|
|
||||||
None => {
|
|
||||||
debug!("assemble_builtin_bound_candidates: no upvar types available yet");
|
|
||||||
Ok(AmbiguousBuiltin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyStruct(def_id, substs) => {
|
ty::TyStruct(def_id, substs) => {
|
||||||
|
@ -1819,7 +1797,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
/// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
|
/// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
|
||||||
/// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
|
/// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
|
||||||
/// ```
|
/// ```
|
||||||
fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option<Vec<Ty<'tcx>>> {
|
fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
|
||||||
match t.sty {
|
match t.sty {
|
||||||
ty::TyUint(_) |
|
ty::TyUint(_) |
|
||||||
ty::TyInt(_) |
|
ty::TyInt(_) |
|
||||||
|
@ -1831,7 +1809,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
ty::TyInfer(ty::IntVar(_)) |
|
ty::TyInfer(ty::IntVar(_)) |
|
||||||
ty::TyInfer(ty::FloatVar(_)) |
|
ty::TyInfer(ty::FloatVar(_)) |
|
||||||
ty::TyChar => {
|
ty::TyChar => {
|
||||||
Some(Vec::new())
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyTrait(..) |
|
ty::TyTrait(..) |
|
||||||
|
@ -1848,56 +1826,56 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyBox(referent_ty) => { // Box<T>
|
ty::TyBox(referent_ty) => { // Box<T>
|
||||||
Some(vec![referent_ty])
|
vec![referent_ty]
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) |
|
ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) |
|
||||||
ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => {
|
ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => {
|
||||||
Some(vec![element_ty])
|
vec![element_ty]
|
||||||
},
|
},
|
||||||
|
|
||||||
ty::TyArray(element_ty, _) | ty::TySlice(element_ty) => {
|
ty::TyArray(element_ty, _) | ty::TySlice(element_ty) => {
|
||||||
Some(vec![element_ty])
|
vec![element_ty]
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyTuple(ref tys) => {
|
ty::TyTuple(ref tys) => {
|
||||||
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
||||||
Some(tys.clone())
|
tys.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyClosure(def_id, ref substs) => {
|
ty::TyClosure(def_id, ref substs) => {
|
||||||
|
// FIXME(#27086). We are invariant w/r/t our
|
||||||
|
// substs.func_substs, but we don't see them as
|
||||||
|
// constituent types; this seems RIGHT but also like
|
||||||
|
// something that a normal type couldn't simulate. Is
|
||||||
|
// this just a gap with the way that PhantomData and
|
||||||
|
// OIBIT interact? That is, there is no way to say
|
||||||
|
// "make me invariant with respect to this TYPE, but
|
||||||
|
// do not act as though I can reach it"
|
||||||
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
|
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
|
||||||
|
substs.upvar_tys.clone()
|
||||||
// TODO
|
|
||||||
match self.infcx.closure_upvars(def_id, substs) {
|
|
||||||
Some(upvars) => {
|
|
||||||
Some(upvars.iter().map(|c| c.ty).collect())
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for `PhantomData<T>`, we pass `T`
|
// for `PhantomData<T>`, we pass `T`
|
||||||
ty::TyStruct(def_id, substs)
|
ty::TyStruct(def_id, substs)
|
||||||
if Some(def_id) == self.tcx().lang_items.phantom_data() =>
|
if Some(def_id) == self.tcx().lang_items.phantom_data() =>
|
||||||
{
|
{
|
||||||
Some(substs.types.get_slice(TypeSpace).to_vec())
|
substs.types.get_slice(TypeSpace).to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyStruct(def_id, substs) => {
|
ty::TyStruct(def_id, substs) => {
|
||||||
Some(self.tcx().struct_fields(def_id, substs).iter()
|
self.tcx().struct_fields(def_id, substs)
|
||||||
.map(|f| f.mt.ty)
|
.iter()
|
||||||
.collect())
|
.map(|f| f.mt.ty)
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyEnum(def_id, substs) => {
|
ty::TyEnum(def_id, substs) => {
|
||||||
Some(self.tcx().substd_enum_variants(def_id, substs)
|
self.tcx().substd_enum_variants(def_id, substs)
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|variant| &variant.args)
|
.flat_map(|variant| &variant.args)
|
||||||
.map(|&ty| ty)
|
.map(|&ty| ty)
|
||||||
.collect())
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2147,15 +2125,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
// binder is moved below
|
// binder is moved below
|
||||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
|
let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
|
||||||
match self.constituent_types_for_ty(self_ty) {
|
let types = self.constituent_types_for_ty(self_ty);
|
||||||
Some(types) => self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)),
|
self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types))
|
||||||
None => {
|
|
||||||
self.tcx().sess.bug(
|
|
||||||
&format!(
|
|
||||||
"asked to confirm default implementation for ambiguous type: {:?}",
|
|
||||||
self_ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_default_impl_object_candidate(&mut self,
|
fn confirm_default_impl_object_candidate(&mut self,
|
||||||
|
|
|
@ -4247,12 +4247,8 @@ impl<'tcx> TyS<'tcx> {
|
||||||
apply_lang_items(cx, did, res)
|
apply_lang_items(cx, did, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
TyClosure(did, ref substs) => {
|
TyClosure(_, ref substs) => {
|
||||||
// TODO
|
TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache))
|
||||||
let param_env = cx.empty_parameter_environment();
|
|
||||||
let infcx = infer::new_infer_ctxt(cx, &cx.tables, Some(param_env), false);
|
|
||||||
let upvars = infcx.closure_upvars(did, substs).unwrap();
|
|
||||||
TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TyTuple(ref tys) => {
|
TyTuple(ref tys) => {
|
||||||
|
@ -6007,62 +6003,6 @@ impl<'tcx> ctxt<'tcx> {
|
||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of `ClosureUpvar`s for each upvar.
|
|
||||||
pub fn closure_upvars<'a>(typer: &infer::InferCtxt<'a, 'tcx>,
|
|
||||||
closure_id: ast::DefId,
|
|
||||||
substs: &ClosureSubsts<'tcx>)
|
|
||||||
-> Option<Vec<ClosureUpvar<'tcx>>>
|
|
||||||
{
|
|
||||||
// Presently an unboxed closure type cannot "escape" out of a
|
|
||||||
// function, so we will only encounter ones that originated in the
|
|
||||||
// local crate or were inlined into it along with some function.
|
|
||||||
// This may change if abstract return types of some sort are
|
|
||||||
// implemented.
|
|
||||||
assert!(closure_id.krate == ast::LOCAL_CRATE);
|
|
||||||
let tcx = typer.tcx;
|
|
||||||
match tcx.freevars.borrow().get(&closure_id.node) {
|
|
||||||
None => Some(vec![]),
|
|
||||||
Some(ref freevars) => {
|
|
||||||
freevars.iter()
|
|
||||||
.map(|freevar| {
|
|
||||||
let freevar_def_id = freevar.def.def_id();
|
|
||||||
let freevar_ty = match typer.node_ty(freevar_def_id.node) {
|
|
||||||
Ok(t) => { t }
|
|
||||||
Err(()) => { return None; }
|
|
||||||
};
|
|
||||||
let freevar_ty = freevar_ty.subst(tcx, &substs.func_substs);
|
|
||||||
|
|
||||||
let upvar_id = ty::UpvarId {
|
|
||||||
var_id: freevar_def_id.node,
|
|
||||||
closure_expr_id: closure_id.node
|
|
||||||
};
|
|
||||||
|
|
||||||
typer.upvar_capture(upvar_id).map(|capture| {
|
|
||||||
let freevar_ref_ty = match capture {
|
|
||||||
UpvarCapture::ByValue => {
|
|
||||||
freevar_ty
|
|
||||||
}
|
|
||||||
UpvarCapture::ByRef(borrow) => {
|
|
||||||
tcx.mk_ref(tcx.mk_region(borrow.region),
|
|
||||||
ty::TypeAndMut {
|
|
||||||
ty: freevar_ty,
|
|
||||||
mutbl: borrow.kind.to_mutbl_lossy(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ClosureUpvar {
|
|
||||||
def: freevar.def,
|
|
||||||
span: freevar.span,
|
|
||||||
ty: freevar_ref_ty,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the repeat count for a repeating vector expression.
|
// Returns the repeat count for a repeating vector expression.
|
||||||
pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize {
|
pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize {
|
||||||
let hint = UncheckedExprHint(self.types.usize);
|
let hint = UncheckedExprHint(self.types.usize);
|
||||||
|
|
|
@ -665,22 +665,32 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||||
TyClosure(ref did, ref substs) => ty::tls::with(|tcx| {
|
TyClosure(ref did, ref substs) => ty::tls::with(|tcx| {
|
||||||
try!(write!(f, "[closure"));
|
try!(write!(f, "[closure"));
|
||||||
|
|
||||||
// TODO consider changing this to print out the upvar types instead
|
if did.krate == ast::LOCAL_CRATE {
|
||||||
|
try!(write!(f, "@{:?}", tcx.map.span(did.node)));
|
||||||
let closure_tys = &tcx.tables.borrow().closure_tys;
|
let mut sep = " ";
|
||||||
try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| {
|
try!(tcx.with_freevars(did.node, |freevars| {
|
||||||
tcx.lift(&substs.func_substs).map(|substs| sig.subst(tcx, substs))
|
for (freevar, upvar_ty) in freevars.iter().zip(&substs.upvar_tys) {
|
||||||
}).map(|sig| {
|
let node_id = freevar.def.local_node_id();
|
||||||
fn_sig(f, &sig.0.inputs, false, sig.0.output)
|
try!(write!(f,
|
||||||
}).unwrap_or_else(|| {
|
"{}{}:{}",
|
||||||
if did.krate == ast::LOCAL_CRATE {
|
sep,
|
||||||
try!(write!(f, " {:?}", tcx.map.span(did.node)));
|
tcx.local_var_name_str(node_id),
|
||||||
|
upvar_ty));
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
// cross-crate closure types should only be
|
||||||
|
// visible in trans bug reports, I imagine.
|
||||||
|
try!(write!(f, "@{:?}", did));
|
||||||
|
let mut sep = " ";
|
||||||
|
for (index, upvar_ty) in substs.upvar_tys.iter().enumerate() {
|
||||||
|
try!(write!(f, "{}{}:{}", sep, index, upvar_ty));
|
||||||
|
sep = ", ";
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
if verbose() {
|
|
||||||
try!(write!(f, " id={:?}", did));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}),
|
}),
|
||||||
TyArray(ty, sz) => write!(f, "[{}; {}]", ty, sz),
|
TyArray(ty, sz) => write!(f, "[{}; {}]", ty, sz),
|
||||||
|
|
|
@ -48,7 +48,6 @@ use std::rc::Rc;
|
||||||
use llvm::{ValueRef, True, IntEQ, IntNE};
|
use llvm::{ValueRef, True, IntEQ, IntNE};
|
||||||
use back::abi::FAT_PTR_ADDR;
|
use back::abi::FAT_PTR_ADDR;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::infer;
|
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::ty::Disr;
|
use middle::ty::Disr;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -221,11 +220,8 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
|
|
||||||
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
|
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
|
||||||
}
|
}
|
||||||
ty::TyClosure(def_id, ref substs) => {
|
ty::TyClosure(_, ref substs) => {
|
||||||
let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables);
|
Univariant(mk_struct(cx, &substs.upvar_tys, false, t), 0)
|
||||||
let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO
|
|
||||||
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
|
|
||||||
Univariant(mk_struct(cx, &upvar_types[..], false, t), 0)
|
|
||||||
}
|
}
|
||||||
ty::TyEnum(def_id, substs) => {
|
ty::TyEnum(def_id, substs) => {
|
||||||
let cases = get_cases(cx.tcx(), def_id, substs);
|
let cases = get_cases(cx.tcx(), def_id, substs);
|
||||||
|
@ -441,12 +437,8 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
|
||||||
// Perhaps one of the upvars of this struct is non-zero
|
// Perhaps one of the upvars of this struct is non-zero
|
||||||
// Let's recurse and find out!
|
// Let's recurse and find out!
|
||||||
ty::TyClosure(def_id, ref substs) => {
|
ty::TyClosure(_, ref substs) => {
|
||||||
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
|
for (j, &ty) in substs.upvar_tys.iter().enumerate() {
|
||||||
let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO
|
|
||||||
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
for (j, &ty) in upvar_types.iter().enumerate() {
|
|
||||||
if let Some(mut fpath) = find_discr_field_candidate(tcx, ty, path.clone()) {
|
if let Some(mut fpath) = find_discr_field_candidate(tcx, ty, path.clone()) {
|
||||||
fpath.push(j);
|
fpath.push(j);
|
||||||
return Some(fpath);
|
return Some(fpath);
|
||||||
|
|
|
@ -37,7 +37,6 @@ use llvm;
|
||||||
use metadata::{csearch, encoder, loader};
|
use metadata::{csearch, encoder, loader};
|
||||||
use middle::astencode;
|
use middle::astencode;
|
||||||
use middle::cfg;
|
use middle::cfg;
|
||||||
use middle::infer;
|
|
||||||
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
|
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
|
||||||
use middle::weak_lang_items;
|
use middle::weak_lang_items;
|
||||||
use middle::pat_util::simple_identifier;
|
use middle::pat_util::simple_identifier;
|
||||||
|
@ -470,13 +469,11 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::TyClosure(def_id, ref substs) => { // TODO
|
ty::TyClosure(_, ref substs) => {
|
||||||
let repr = adt::represent_type(cx.ccx(), t);
|
let repr = adt::represent_type(cx.ccx(), t);
|
||||||
let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables);
|
for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() {
|
||||||
let upvars = infcx.closure_upvars(def_id, substs).unwrap();
|
|
||||||
for (i, upvar) in upvars.iter().enumerate() {
|
|
||||||
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
|
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
|
||||||
cx = f(cx, llupvar, upvar.ty);
|
cx = f(cx, llupvar, upvar_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::TyArray(_, n) => {
|
ty::TyArray(_, n) => {
|
||||||
|
|
|
@ -53,25 +53,26 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||||
opt_kind,
|
opt_kind,
|
||||||
expected_sig);
|
expected_sig);
|
||||||
|
|
||||||
let mut fn_ty = astconv::ty_of_closure(
|
let mut fn_ty = astconv::ty_of_closure(fcx,
|
||||||
fcx,
|
ast::Unsafety::Normal,
|
||||||
ast::Unsafety::Normal,
|
decl,
|
||||||
decl,
|
abi::RustCall,
|
||||||
abi::RustCall,
|
expected_sig);
|
||||||
expected_sig);
|
|
||||||
|
|
||||||
let freevar_tys =
|
// Create type variables (for now) to represent the transformed
|
||||||
fcx.tcx().with_freevars(expr.id, |fv| {
|
// types of upvars. These will be unified during the upvar
|
||||||
fv.iter()
|
// inference phase (`upvar.rs`).
|
||||||
.map(|_| fcx.tcx().types.bool) // TODO
|
let num_upvars = fcx.tcx().with_freevars(expr.id, |fv| fv.len());
|
||||||
.collect()
|
let upvar_tys = fcx.infcx().next_ty_vars(num_upvars);
|
||||||
});
|
|
||||||
|
debug!("check_closure: expr.id={:?} upvar_tys={:?}",
|
||||||
|
expr.id, upvar_tys);
|
||||||
|
|
||||||
let closure_type =
|
let closure_type =
|
||||||
fcx.ccx.tcx.mk_closure(
|
fcx.ccx.tcx.mk_closure(
|
||||||
expr_def_id,
|
expr_def_id,
|
||||||
fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()),
|
fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()),
|
||||||
freevar_tys);
|
upvar_tys);
|
||||||
|
|
||||||
fcx.write_ty(expr.id, closure_type);
|
fcx.write_ty(expr.id, closure_type);
|
||||||
|
|
||||||
|
|
|
@ -382,7 +382,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
||||||
self.region_bound_pairs.push((r_a, generic_b.clone()));
|
self.region_bound_pairs.push((r_a, generic_b.clone()));
|
||||||
}
|
}
|
||||||
implicator::Implication::RegionSubRegion(..) |
|
implicator::Implication::RegionSubRegion(..) |
|
||||||
implicator::Implication::RegionSubClosure(..) |
|
|
||||||
implicator::Implication::Predicate(..) => {
|
implicator::Implication::Predicate(..) => {
|
||||||
// In principle, we could record (and take
|
// In principle, we could record (and take
|
||||||
// advantage of) every relationship here, but
|
// advantage of) every relationship here, but
|
||||||
|
@ -1425,9 +1424,6 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
||||||
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
|
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
|
||||||
generic_must_outlive(rcx, o1, r_a, generic_b);
|
generic_must_outlive(rcx, o1, r_a, generic_b);
|
||||||
}
|
}
|
||||||
implicator::Implication::RegionSubClosure(_, r_a, def_id, substs) => {
|
|
||||||
closure_must_outlive(rcx, origin.clone(), r_a, def_id, substs);
|
|
||||||
}
|
|
||||||
implicator::Implication::Predicate(def_id, predicate) => {
|
implicator::Implication::Predicate(def_id, predicate) => {
|
||||||
let cause = traits::ObligationCause::new(origin.span(),
|
let cause = traits::ObligationCause::new(origin.span(),
|
||||||
rcx.body_id,
|
rcx.body_id,
|
||||||
|
@ -1439,23 +1435,6 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
|
||||||
region: ty::Region,
|
|
||||||
def_id: ast::DefId,
|
|
||||||
substs: &'tcx ty::ClosureSubsts<'tcx>) {
|
|
||||||
debug!("closure_must_outlive(region={:?}, def_id={:?}, substs={:?})",
|
|
||||||
region, def_id, substs);
|
|
||||||
|
|
||||||
let upvars = rcx.fcx.infcx().closure_upvars(def_id, substs).unwrap();
|
|
||||||
for upvar in upvars {
|
|
||||||
let var_id = upvar.def.def_id().local_id();
|
|
||||||
type_must_outlive(
|
|
||||||
rcx, infer::FreeVariable(origin.span(), var_id),
|
|
||||||
upvar.ty, region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
origin: infer::SubregionOrigin<'tcx>,
|
||||||
region: ty::Region,
|
region: ty::Region,
|
||||||
|
|
|
@ -42,9 +42,10 @@
|
||||||
|
|
||||||
use super::FnCtxt;
|
use super::FnCtxt;
|
||||||
|
|
||||||
|
use check::demand;
|
||||||
use middle::expr_use_visitor as euv;
|
use middle::expr_use_visitor as euv;
|
||||||
use middle::mem_categorization as mc;
|
use middle::mem_categorization as mc;
|
||||||
use middle::ty::{self};
|
use middle::ty::{self, Ty};
|
||||||
use middle::infer::{InferCtxt, UpvarRegion};
|
use middle::infer::{InferCtxt, UpvarRegion};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -178,54 +179,55 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
|
||||||
AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds }
|
AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_closure(&mut self, id: ast::NodeId, decl: &ast::FnDecl, body: &ast::Block) {
|
fn analyze_closure(&mut self,
|
||||||
|
id: ast::NodeId,
|
||||||
|
span: Span,
|
||||||
|
decl: &ast::FnDecl,
|
||||||
|
body: &ast::Block) {
|
||||||
/*!
|
/*!
|
||||||
* Analysis starting point.
|
* Analysis starting point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id);
|
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut euv = euv::ExprUseVisitor::new(self, self.fcx.infcx());
|
||||||
|
euv.walk_fn(decl, body);
|
||||||
|
}
|
||||||
|
|
||||||
let mut euv = euv::ExprUseVisitor::new(self, self.fcx.infcx());
|
// Now that we've analyzed the closure, we know how each
|
||||||
euv.walk_fn(decl, body);
|
// variable is borrowed, and we know what traits the closure
|
||||||
|
// implements (Fn vs FnMut etc). We now have some updates to do
|
||||||
|
// with that information.
|
||||||
|
//
|
||||||
|
// Note that no closure type C may have an upvar of type C
|
||||||
|
// (though it may reference itself via a trait object). This
|
||||||
|
// results from the desugaring of closures to a struct like
|
||||||
|
// `Foo<..., UV0...UVn>`. If one of those upvars referenced
|
||||||
|
// C, then the type would have infinite size (and the
|
||||||
|
// inference algorithm will reject it).
|
||||||
|
|
||||||
// If we had not yet settled on a closure kind for this closure,
|
// Extract the type variables UV0...UVn.
|
||||||
// then we should have by now. Process and remove any deferred resolutions.
|
let closure_substs = match self.fcx.node_ty(id).sty {
|
||||||
//
|
ty::TyClosure(_, ref substs) => substs,
|
||||||
// Interesting fact: all calls to this closure must come
|
ref t => {
|
||||||
// *after* its definition. Initially, I thought that some
|
self.fcx.tcx().sess.span_bug(
|
||||||
// kind of fixed-point iteration would be required, due to the
|
span,
|
||||||
// possibility of twisted examples like this one:
|
&format!("type of closure expr {:?} is not a closure {:?}",
|
||||||
//
|
id, t));
|
||||||
// ```rust
|
}
|
||||||
// let mut closure0 = None;
|
};
|
||||||
// let vec = vec!(1, 2, 3);
|
|
||||||
//
|
// Equate the type variables with the actual types.
|
||||||
// loop {
|
let final_upvar_tys = self.final_upvar_tys(id);
|
||||||
// {
|
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
|
||||||
// let closure1 = || {
|
id, closure_substs, final_upvar_tys);
|
||||||
// match closure0.take() {
|
for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) {
|
||||||
// Some(c) => {
|
demand::eqtype(self.fcx, span, final_upvar_ty, upvar_ty);
|
||||||
// return c(); // (*) call to `closure0` before it is defined
|
}
|
||||||
// }
|
|
||||||
// None => { }
|
// Now we must process and remove any deferred resolutions,
|
||||||
// }
|
// since we have a concrete closure kind.
|
||||||
// };
|
|
||||||
// closure1();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// closure0 = || vec;
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// However, this turns out to be wrong. Examples like this
|
|
||||||
// fail to compile because the type of the variable `c` above
|
|
||||||
// is an inference variable. And in fact since closure types
|
|
||||||
// cannot be written, there is no way to make this example
|
|
||||||
// work without a boxed closure. This implies that we can't
|
|
||||||
// have two closures that recursively call one another without
|
|
||||||
// some form of boxing (and hence explicit writing of a
|
|
||||||
// closure kind) involved. Huzzah. -nmatsakis
|
|
||||||
let closure_def_id = ast_util::local_def(id);
|
let closure_def_id = ast_util::local_def(id);
|
||||||
if self.closures_with_inferred_kinds.contains(&id) {
|
if self.closures_with_inferred_kinds.contains(&id) {
|
||||||
let mut deferred_call_resolutions =
|
let mut deferred_call_resolutions =
|
||||||
|
@ -236,6 +238,42 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a list of `ClosureUpvar`s for each upvar.
|
||||||
|
fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
|
||||||
|
// Presently an unboxed closure type cannot "escape" out of a
|
||||||
|
// function, so we will only encounter ones that originated in the
|
||||||
|
// local crate or were inlined into it along with some function.
|
||||||
|
// This may change if abstract return types of some sort are
|
||||||
|
// implemented.
|
||||||
|
let tcx = self.fcx.tcx();
|
||||||
|
tcx.with_freevars(closure_id, |freevars| {
|
||||||
|
freevars.iter()
|
||||||
|
.map(|freevar| {
|
||||||
|
let freevar_def_id = freevar.def.def_id();
|
||||||
|
let freevar_ty = self.fcx.node_ty(freevar_def_id.node);
|
||||||
|
let upvar_id = ty::UpvarId {
|
||||||
|
var_id: freevar_def_id.node,
|
||||||
|
closure_expr_id: closure_id
|
||||||
|
};
|
||||||
|
let capture = self.fcx.infcx().upvar_capture(upvar_id).unwrap();
|
||||||
|
|
||||||
|
debug!("freevar_def_id={:?} freevar_ty={:?} capture={:?}",
|
||||||
|
freevar_def_id, freevar_ty, capture);
|
||||||
|
|
||||||
|
match capture {
|
||||||
|
ty::UpvarCapture::ByValue => freevar_ty,
|
||||||
|
ty::UpvarCapture::ByRef(borrow) =>
|
||||||
|
tcx.mk_ref(tcx.mk_region(borrow.region),
|
||||||
|
ty::TypeAndMut {
|
||||||
|
ty: freevar_ty,
|
||||||
|
mutbl: borrow.kind.to_mutbl_lossy(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn adjust_upvar_borrow_kind_for_consume(&self,
|
fn adjust_upvar_borrow_kind_for_consume(&self,
|
||||||
cmt: mc::cmt<'tcx>,
|
cmt: mc::cmt<'tcx>,
|
||||||
mode: euv::ConsumeMode)
|
mode: euv::ConsumeMode)
|
||||||
|
@ -267,10 +305,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
|
||||||
// to move out of an upvar, this must be a FnOnce closure
|
// to move out of an upvar, this must be a FnOnce closure
|
||||||
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
|
self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
|
||||||
|
|
||||||
let upvar_capture_map = &mut self.fcx
|
let upvar_capture_map =
|
||||||
.inh
|
&mut self.fcx.inh.tables.borrow_mut().upvar_capture_map;
|
||||||
.tables.borrow_mut()
|
|
||||||
.upvar_capture_map;
|
|
||||||
upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
|
upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
|
||||||
}
|
}
|
||||||
mc::NoteClosureEnv(upvar_id) => {
|
mc::NoteClosureEnv(upvar_id) => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<FnMut()->(isize) + 'a> {
|
||||||
|
|
||||||
fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
|
fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
|
||||||
// This is illegal, because the region bound on `proc` is 'static.
|
// This is illegal, because the region bound on `proc` is 'static.
|
||||||
Box::new(move|| { *x }) //~ ERROR captured variable `x` does not outlive the enclosing closure
|
Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue