From 69d62e04e524d4b202b7fdce791e1418a4adbb38 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Jul 2015 05:32:45 -0400 Subject: [PATCH 01/10] introduce a Vec to TyClosure for storing upvar types --- src/librustc/metadata/tydecode.rs | 7 ++++- src/librustc/metadata/tyencode.rs | 6 ++++- src/librustc/middle/fast_reject.rs | 2 +- src/librustc/middle/implicator.rs | 3 ++- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/traits/mod.rs | 4 ++- src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/traits/select.rs | 26 +++++++++++-------- src/librustc/middle/ty.rs | 18 ++++++++----- src/librustc/middle/ty_fold.rs | 6 +++-- src/librustc/middle/ty_relate/mod.rs | 13 +++++++--- src/librustc/middle/ty_walk.rs | 7 +++-- src/librustc/util/ppaux.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_trans/trans/adt.rs | 8 +++--- src/librustc_trans/trans/attributes.rs | 2 +- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/closure.rs | 11 +++++--- .../trans/debuginfo/metadata.rs | 4 +-- src/librustc_trans/trans/declare.rs | 2 +- src/librustc_trans/trans/meth.rs | 3 +++ src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/closure.rs | 14 ++++++++-- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 4 +-- src/librustc_typeck/coherence/mod.rs | 2 +- 27 files changed, 104 insertions(+), 54 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index ee9e199a6c52a..72e1525b506d1 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -564,8 +564,13 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w assert_eq!(next(st), '['); let did = parse_def_(st, ClosureSource, conv); let substs = parse_substs_(st, conv); + let mut tys = vec![]; + while peek(st) != '.' { + tys.push(parse_ty_(st, conv)); + } + assert_eq!(next(st), '.'); assert_eq!(next(st), ']'); - return st.tcx.mk_closure(did, st.tcx.mk_substs(substs)); + return st.tcx.mk_closure(did, st.tcx.mk_substs(substs), tys); } 'P' => { assert_eq!(next(st), '['); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index e29c0f2b83705..77b5306c36e43 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -143,9 +143,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { enc_substs(w, cx, substs); mywrite!(w, "]"); } - ty::TyClosure(def, substs) => { + ty::TyClosure(def, substs, ref tys) => { mywrite!(w, "k[{}|", (cx.ds)(def)); enc_substs(w, cx, substs); + for ty in tys { + enc_ty(w, cx, ty); + } + mywrite!(w, "."); mywrite!(w, "]"); } ty::TyProjection(ref data) => { diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index de7582a137166..4635e406c4122 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -76,7 +76,7 @@ pub fn simplify_type(tcx: &ty::ctxt, Err(msg) => tcx.sess.fatal(&msg), } } - ty::TyClosure(def_id, _) => { + ty::TyClosure(def_id, _, _) => { Some(ClosureSimplifiedType(def_id)) } ty::TyTuple(ref tys) => { diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index 18059848481e6..b6a8037fe033e 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -96,7 +96,8 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { // No borrowed content reachable here. } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { + // TODO remove RegionSubClosure let &(r_a, opt_ty) = self.stack.last().unwrap(); self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs)); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 4345649de0c81..fbb80fef9e6df 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1493,7 +1493,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> { let fn_ty = self.ir.tcx.node_id_to_type(id); match fn_ty.sty { - ty::TyClosure(closure_def_id, substs) => + ty::TyClosure(closure_def_id, substs, _) => self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), _ => fn_ty.fn_ret() } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bf47396bb9f65..4ba154b1046f3 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -584,7 +584,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { def::DefUpvar(var_id, fn_node_id) => { let ty = try!(self.node_ty(fn_node_id)); match ty.sty { - ty::TyClosure(closure_id, _) => { + ty::TyClosure(closure_id, _, _) => { match self.typer.closure_kind(closure_id) { Some(kind) => { self.cat_upvar(id, span, var_id, fn_node_id, kind) diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 148b27adf64b2..ea2dee7615935 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -271,6 +271,7 @@ pub struct VtableImplData<'tcx, N> { pub struct VtableClosureData<'tcx, N> { pub closure_def_id: ast::DefId, pub substs: subst::Substs<'tcx>, + pub upvar_tys: Vec>, /// Nested obligations. This can be non-empty if the closure /// signature contains associated types. pub nested: Vec @@ -548,7 +549,8 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableClosure(c) => VtableClosure(VtableClosureData { closure_def_id: c.closure_def_id, substs: c.substs, - nested: c.nested.into_iter().map(f).collect() + nested: c.nested.into_iter().map(f).collect(), + upvar_tys: c.upvar_tys, }) } } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index cd38e9d0d31bc..b678aa405a89c 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -154,7 +154,7 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", self_ty.sty); match self_ty.sty { - ty::TyClosure(closure_def_id, substs) => { + ty::TyClosure(closure_def_id, substs, _) => { let closure_typer = selcx.closure_typer(); let closure_type = closure_typer.closure_type(closure_def_id, substs); let ty::Binder((_, ret_type)) = diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 81e59f57ae7de..af41e205aec66 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -201,7 +201,7 @@ enum SelectionCandidate<'tcx> { /// Implementation of a `Fn`-family trait by one of the /// anonymous types generated for a `||` expression. - ClosureCandidate(/* closure */ ast::DefId, Substs<'tcx>), + ClosureCandidate(/* closure */ ast::DefId, &'tcx Substs<'tcx>, &'tcx Vec>), /// Implementation of a `Fn`-family trait by one of the anonymous /// types generated for a fn pointer type (e.g., `fn(int)->int`) @@ -348,7 +348,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // lifetimes can appear inside the self-type. let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.sty { - ty::TyClosure(id, ref substs) => (id, substs.clone()), + ty::TyClosure(id, ref substs, _) => (id, substs.clone()), _ => { return; } }; assert!(!substs.has_escaping_regions()); @@ -1142,8 +1142,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.sty { - ty::TyClosure(id, substs) => (id, substs), + let (closure_def_id, substs, upvar_tys) = match self_ty.sty { + ty::TyClosure(id, substs, ref upvar_tys) => (id, substs, upvar_tys), ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); candidates.ambiguous = true; @@ -1161,8 +1161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(closure_kind) => { debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate(closure_def_id, - substs.clone())); + candidates.vec.push(ClosureCandidate(closure_def_id, substs, upvar_tys)); } } None => { @@ -1704,7 +1703,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet ty::TyTuple(ref tys) => ok_if(tys.clone()), - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { // FIXME -- This case is tricky. In the case of by-ref // closures particularly, we need the results of // inference to decide how to reflect the type of each @@ -1730,6 +1729,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return ok_if(Vec::new()); } + // TODO match self.infcx.closure_upvars(def_id, substs) { Some(upvars) => ok_if(upvars.iter().map(|c| c.ty).collect()), None => { @@ -1865,9 +1865,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(tys.clone()) } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); + // TODO match self.infcx.closure_upvars(def_id, substs) { Some(upvars) => { Some(upvars.iter().map(|c| c.ty).collect()) @@ -2014,9 +2015,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableImpl(vtable_impl)) } - ClosureCandidate(closure_def_id, substs) => { + ClosureCandidate(closure_def_id, substs, upvar_tys) => { let vtable_closure = - try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs)); + try!(self.confirm_closure_candidate(obligation, closure_def_id, + &substs, upvar_tys)); Ok(VtableClosure(vtable_closure)) } @@ -2365,7 +2367,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_closure_candidate(&mut self, obligation: &TraitObligation<'tcx>, closure_def_id: ast::DefId, - substs: &Substs<'tcx>) + substs: &Substs<'tcx>, + upvar_tys: &'tcx Vec>) -> Result>, SelectionError<'tcx>> { @@ -2391,6 +2394,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableClosureData { closure_def_id: closure_def_id, substs: substs.clone(), + upvar_tys: upvar_tys.clone(), nested: obligations }) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 64e707f6264e6..17d55737114fb 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1767,7 +1767,7 @@ pub enum TypeVariants<'tcx> { /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. - TyClosure(DefId, &'tcx Substs<'tcx>), + TyClosure(DefId, &'tcx Substs<'tcx>, Vec>), /// A tuple type. For example, `(i32, bool)`. TyTuple(Vec>), @@ -3214,10 +3214,11 @@ impl FlagComputation { } } - &TyClosure(_, substs) => { + &TyClosure(_, substs, ref tys) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); self.add_substs(substs); + self.add_tys(tys); } &TyInfer(_) => { @@ -3659,9 +3660,12 @@ impl<'tcx> ctxt<'tcx> { self.mk_ty(TyStruct(struct_id, substs)) } - pub fn mk_closure(&self, closure_id: ast::DefId, substs: &'tcx Substs<'tcx>) + pub fn mk_closure(&self, + closure_id: ast::DefId, + substs: &'tcx Substs<'tcx>, + tys: Vec>) -> Ty<'tcx> { - self.mk_ty(TyClosure(closure_id, substs)) + self.mk_ty(TyClosure(closure_id, substs, tys)) } pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> { @@ -3928,7 +3932,7 @@ impl<'tcx> TyS<'tcx> { TyTrait(ref tt) => Some(tt.principal_def_id()), TyStruct(id, _) | TyEnum(id, _) | - TyClosure(id, _) => Some(id), + TyClosure(id, _, _) => Some(id), _ => None } } @@ -4146,7 +4150,7 @@ impl<'tcx> TyS<'tcx> { apply_lang_items(cx, did, res) } - TyClosure(did, substs) => { + TyClosure(did, substs, _) => { 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(); @@ -6378,7 +6382,7 @@ impl<'tcx> ctxt<'tcx> { } TyInfer(_) => unreachable!(), TyError => byte!(21), - TyClosure(d, _) => { + TyClosure(d, _, _) => { byte!(22); did(state, d); } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index eae2bb4966408..87b5fcbd28e90 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -450,6 +450,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureDa closure_def_id: self.closure_def_id, substs: self.substs.fold_with(folder), nested: self.nested.fold_with(folder), + upvar_tys: self.upvar_tys.fold_with(folder), } } } @@ -602,9 +603,10 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, let substs = substs.fold_with(this); ty::TyStruct(did, this.tcx().mk_substs(substs)) } - ty::TyClosure(did, ref substs) => { + ty::TyClosure(did, ref substs, ref tys) => { let s = substs.fold_with(this); - ty::TyClosure(did, this.tcx().mk_substs(s)) + let tys = tys.fold_with(this); + ty::TyClosure(did, this.tcx().mk_substs(s), tys) } ty::TyProjection(ref data) => { ty::TyProjection(data.fold_with(this)) diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs index 0159801d5beea..33cddc978d9bb 100644 --- a/src/librustc/middle/ty_relate/mod.rs +++ b/src/librustc/middle/ty_relate/mod.rs @@ -48,6 +48,12 @@ pub trait TypeRelation<'a,'tcx> : Sized { Relate::relate(self, a, b) } + /// Relete elements of two slices pairwise. + fn relate_zip>(&mut self, a: &[T], b: &[T]) -> RelateResult<'tcx, Vec> { + assert_eq!(a.len(), b.len()); + a.iter().zip(b).map(|(a, b)| self.relate(a, b)).collect() + } + /// Switch variance for the purpose of relating `a` and `b`. fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -500,15 +506,16 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, Ok(tcx.mk_struct(a_id, tcx.mk_substs(substs))) } - (&ty::TyClosure(a_id, a_substs), - &ty::TyClosure(b_id, b_substs)) + (&ty::TyClosure(a_id, a_substs, ref a_tys), + &ty::TyClosure(b_id, b_substs, ref b_tys)) if a_id == b_id => { // All TyClosure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let substs = try!(relate_substs(relation, None, a_substs, b_substs)); - Ok(tcx.mk_closure(a_id, tcx.mk_substs(substs))) + let tys = try!(relation.relate_zip(a_tys, b_tys)); + Ok(tcx.mk_closure(a_id, tcx.mk_substs(substs), tys)) } (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 3e9a402f9499c..97f3bd1297197 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -88,10 +88,13 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { }).collect::>()); } ty::TyEnum(_, ref substs) | - ty::TyStruct(_, ref substs) | - ty::TyClosure(_, ref substs) => { + ty::TyStruct(_, ref substs) => { push_reversed(stack, substs.types.as_slice()); } + ty::TyClosure(_, ref substs, ref tys) => { + push_reversed(stack, substs.types.as_slice()); + push_reversed(stack, tys); + } ty::TyTuple(ref ts) => { push_reversed(stack, ts); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index b0510a76385be..d6696e392bcff 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -662,7 +662,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyTrait(ref data) => write!(f, "{}", data), ty::TyProjection(ref data) => write!(f, "{}", data), TyStr => write!(f, "str"), - TyClosure(ref did, substs) => ty::tls::with(|tcx| { + TyClosure(ref did, substs, _) => ty::tls::with(|tcx| { try!(write!(f, "[closure")); let closure_tys = &tcx.tables.borrow().closure_tys; try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6289d50588104..331bcaa8da89b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2529,7 +2529,7 @@ impl LintPass for DropWithReprExtern { match dtor_self_type.sty { ty::TyEnum(self_type_did, _) | ty::TyStruct(self_type_did, _) | - ty::TyClosure(self_type_did, _) => { + ty::TyClosure(self_type_did, _, _) => { let hints = ctx.tcx.lookup_repr_hints(self_type_did); if hints.iter().any(|attr| *attr == attr::ReprExtern) && ctx.tcx.ty_dtor(self_type_did).has_drop_flag() { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 7b2bdee50fe78..985ef2d7b14fc 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -221,9 +221,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor)) } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let upvars = infcx.closure_upvars(def_id, substs).unwrap(); + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); Univariant(mk_struct(cx, &upvar_types[..], false, t), 0) } @@ -441,9 +441,9 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Perhaps one of the upvars of this struct is non-zero // Let's recurse and find out! - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); - let upvars = infcx.closure_upvars(def_id, substs).unwrap(); + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); for (j, &ty) in upvar_types.iter().enumerate() { diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index f8daefa87a5ff..03e7d9e3aa285 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -145,7 +145,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx let function_type; let (fn_sig, abi, env_ty) = match fn_type.sty { ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None), - ty::TyClosure(closure_did, substs) => { + ty::TyClosure(closure_did, substs, _) => { let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); function_type = infcx.closure_type(closure_did, substs); let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 258051357b105..678b5063816c7 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -470,7 +470,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } }) } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { // TODO let repr = adt::represent_type(cx.ccx(), t); let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let upvars = infcx.closure_upvars(def_id, substs).unwrap(); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index f00029ec2ff93..defa0a1d898bf 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -12,6 +12,7 @@ use arena::TypedArena; use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_params}; use middle::infer; +use middle::ty::Ty; use trans::adt; use trans::attributes; use trans::base::*; @@ -142,7 +143,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc // duplicate declarations let function_type = erase_regions(ccx.tcx(), &function_type); let params = match function_type.sty { - ty::TyClosure(_, substs) => &substs.types, + ty::TyClosure(_, substs, _) => &substs.types, _ => unreachable!() }; let mono_id = MonoId { @@ -269,6 +270,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: ast::DefId, substs: Substs<'tcx>, + upvar_tys: Vec>, node: ExprOrMethodCall, param_substs: &'tcx Substs<'tcx>, trait_closure_kind: ty::ClosureKind) @@ -288,6 +290,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, trans_closure_adapter_shim(ccx, closure_def_id, substs, + upvar_tys, closure_kind, trait_closure_kind, llfn) @@ -297,6 +300,7 @@ fn trans_closure_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: ast::DefId, substs: Substs<'tcx>, + upvar_tys: Vec>, llfn_closure_kind: ty::ClosureKind, trait_closure_kind: ty::ClosureKind, llfn: ValueRef) @@ -335,7 +339,7 @@ fn trans_closure_adapter_shim<'a, 'tcx>( // fn call_once(mut self, ...) { call_mut(&mut self, ...) } // // These are both the same at trans time. - trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn) + trans_fn_once_adapter_shim(ccx, closure_def_id, substs, upvar_tys, llfn) } _ => { tcx.sess.bug(&format!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", @@ -349,6 +353,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: ast::DefId, substs: Substs<'tcx>, + upvar_tys: Vec>, llreffn: ValueRef) -> ValueRef { @@ -363,7 +368,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Find a version of the closure type. Substitute static for the // region since it doesn't really matter. let substs = tcx.mk_substs(substs); - let closure_ty = tcx.mk_closure(closure_def_id, substs); + let closure_ty = tcx.mk_closure(closure_def_id, substs, upvar_tys); let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), closure_ty); // Make a version with the type of by-ref closure. diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 5f17197a4b9a7..d0c6c0ab308c4 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -287,7 +287,7 @@ impl<'tcx> TypeMap<'tcx> { } } }, - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let closure_ty = infcx.closure_type(def_id, substs); self.get_unique_type_id_of_closure_type(cx, @@ -811,7 +811,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let upvars = infcx.closure_upvars(def_id, substs).unwrap(); let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index c802de91e38b3..a641302e53fab 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -116,7 +116,7 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, ty::TyBareFn(_, ref f) => { (&f.sig, f.abi, None) } - ty::TyClosure(closure_did, substs) => { + ty::TyClosure(closure_did, substs, _) => { let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); function_type = infcx.closure_type(closure_did, substs); let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 8901361b27976..cf2a226db41eb 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -341,6 +341,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llfn = closure::trans_closure_method(bcx.ccx(), vtable_closure.closure_def_id, vtable_closure.substs, + vtable_closure.upvar_tys, MethodCallKey(method_call), bcx.fcx.param_substs, trait_closure_kind); @@ -641,11 +642,13 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, traits::VtableClosureData { closure_def_id, substs, + upvar_tys, nested: _ }) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); let llfn = closure::trans_closure_method(ccx, closure_def_id, substs, + upvar_tys, ExprId(0), param_substs, trait_closure_kind); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index f32a4fe43d696..955a301340519 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -131,7 +131,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return Some(CallStep::Builtin); } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs, _) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); // Check whether this is a call to a closure where we diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 6d1e9dfacf281..71e51292a7846 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -60,8 +60,18 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, abi::RustCall, expected_sig); - let closure_type = fcx.ccx.tcx.mk_closure(expr_def_id, - fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone())); + let freevar_tys = + fcx.tcx().with_freevars(expr.id, |fv| { + fv.iter() + .map(|_| fcx.tcx().types.bool) // TODO + .collect() + }); + + let closure_type = + fcx.ccx.tcx.mk_closure( + expr_def_id, + fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()), + freevar_tys); fcx.write_ty(expr.id, closure_type); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 7d911cf8b03bc..f37177684d552 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -42,7 +42,7 @@ pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), match dtor_self_type.sty { ty::TyEnum(self_type_did, self_to_impl_substs) | ty::TyStruct(self_type_did, self_to_impl_substs) | - ty::TyClosure(self_type_did, self_to_impl_substs) => { + ty::TyClosure(self_type_did, self_to_impl_substs, _) => { try!(ensure_drop_params_and_item_params_correspond(tcx, drop_impl_did, dtor_generics, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a960123efc6b8..8b9871428c4d1 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -288,7 +288,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } ty::TyEnum(did, _) | ty::TyStruct(did, _) | - ty::TyClosure(did, _) => { + ty::TyClosure(did, _, _) => { self.assemble_inherent_impl_candidates_for_type(did); } ty::TyBox(_) => { @@ -711,7 +711,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let steps = self.steps.clone(); for step in steps.iter() { let closure_def_id = match step.self_ty.sty { - ty::TyClosure(a, _) => a, + ty::TyClosure(a, _, _) => a, _ => continue, }; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 2b800bd9a441f..0878ca1c29562 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { match self_type.ty.sty { ty::TyEnum(type_def_id, _) | ty::TyStruct(type_def_id, _) | - ty::TyClosure(type_def_id, _) => { + ty::TyClosure(type_def_id, _, _) => { tcx.destructor_for_type .borrow_mut() .insert(type_def_id, method_def_id.def_id()); From 1e2677be72e2b0c180ed1be38d1868b4829ad530 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Jul 2015 09:46:35 -0400 Subject: [PATCH 02/10] Introduce ClosureSubsts rather than just having random fields in the TyClosure variant; thread this through wherever closure substitutions are expected, which leads to a net simplification. Simplify trans treatment of closures in particular. --- src/librustc/metadata/tyencode.rs | 6 +- src/librustc/middle/fast_reject.rs | 2 +- src/librustc/middle/implicator.rs | 4 +- src/librustc/middle/infer/mod.rs | 11 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/traits/mod.rs | 4 +- src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/traits/select.rs | 27 ++-- src/librustc/middle/ty.rs | 142 ++++++++++++++++-- src/librustc/middle/ty_fold.rs | 16 +- src/librustc/middle/ty_relate/mod.rs | 23 ++- src/librustc/middle/ty_walk.rs | 6 +- src/librustc/util/ppaux.rs | 7 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_trans/trans/adt.rs | 4 +- src/librustc_trans/trans/attributes.rs | 2 +- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/callee.rs | 7 - src/librustc_trans/trans/closure.rs | 92 ++++-------- src/librustc_trans/trans/consts.rs | 15 +- .../trans/debuginfo/metadata.rs | 4 +- src/librustc_trans/trans/declare.rs | 2 +- src/librustc_trans/trans/expr.rs | 10 +- src/librustc_trans/trans/meth.rs | 7 - src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/dropck.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/regionck.rs | 3 +- src/librustc_typeck/coherence/mod.rs | 2 +- 30 files changed, 256 insertions(+), 159 deletions(-) diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 77b5306c36e43..c77e96f164888 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -143,10 +143,10 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { enc_substs(w, cx, substs); mywrite!(w, "]"); } - ty::TyClosure(def, substs, ref tys) => { + ty::TyClosure(def, ref substs) => { mywrite!(w, "k[{}|", (cx.ds)(def)); - enc_substs(w, cx, substs); - for ty in tys { + enc_substs(w, cx, &substs.func_substs); + for ty in &substs.upvar_tys { enc_ty(w, cx, ty); } mywrite!(w, "."); diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 4635e406c4122..de7582a137166 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -76,7 +76,7 @@ pub fn simplify_type(tcx: &ty::ctxt, Err(msg) => tcx.sess.fatal(&msg), } } - ty::TyClosure(def_id, _, _) => { + ty::TyClosure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } ty::TyTuple(ref tys) => { diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index b6a8037fe033e..8fba98bead479 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -28,7 +28,7 @@ use util::nodemap::FnvHashSet; pub enum Implication<'tcx> { RegionSubRegion(Option>, ty::Region, ty::Region), RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), - RegionSubClosure(Option>, ty::Region, ast::DefId, &'tcx Substs<'tcx>), + RegionSubClosure(Option>, ty::Region, ast::DefId, &'tcx ty::ClosureSubsts<'tcx>), Predicate(ast::DefId, ty::Predicate<'tcx>), } @@ -96,7 +96,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { // No borrowed content reachable here. } - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { // TODO remove RegionSubClosure let &(r_a, opt_ty) = self.stack.last().unwrap(); self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs)); diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index a293170966aac..e6cea4d1b6ac0 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1374,17 +1374,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx> + def_id: ast::DefId, + substs: &ty::ClosureSubsts<'tcx>) + -> ty::ClosureTy<'tcx> { - let closure_ty = self.tables .borrow() .closure_tys .get(&def_id) .unwrap() - .subst(self.tcx, substs); + .subst(self.tcx, &substs.func_substs); if self.normalize { normalize_associated_type(&self.tcx, &closure_ty) @@ -1395,7 +1394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn closure_upvars(&self, def_id: ast::DefId, - substs: &Substs<'tcx>) + substs: &ty::ClosureSubsts<'tcx>) -> Option>> { let result = ty::ctxt::closure_upvars(self, def_id, substs); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index fbb80fef9e6df..7db740798bd40 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1493,7 +1493,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> { let fn_ty = self.ir.tcx.node_id_to_type(id); match fn_ty.sty { - ty::TyClosure(closure_def_id, substs, _) => + ty::TyClosure(closure_def_id, ref substs) => self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), _ => fn_ty.fn_ret() } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 4ba154b1046f3..bf47396bb9f65 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -584,7 +584,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { def::DefUpvar(var_id, fn_node_id) => { let ty = try!(self.node_ty(fn_node_id)); match ty.sty { - ty::TyClosure(closure_id, _, _) => { + ty::TyClosure(closure_id, _) => { match self.typer.closure_kind(closure_id) { Some(kind) => { self.cat_upvar(id, span, var_id, fn_node_id, kind) diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index ea2dee7615935..376430e87c6f0 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -270,8 +270,7 @@ pub struct VtableImplData<'tcx, N> { #[derive(Clone, PartialEq, Eq)] pub struct VtableClosureData<'tcx, N> { pub closure_def_id: ast::DefId, - pub substs: subst::Substs<'tcx>, - pub upvar_tys: Vec>, + pub substs: ty::ClosureSubsts<'tcx>, /// Nested obligations. This can be non-empty if the closure /// signature contains associated types. pub nested: Vec @@ -550,7 +549,6 @@ impl<'tcx, N> Vtable<'tcx, N> { closure_def_id: c.closure_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), - upvar_tys: c.upvar_tys, }) } } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index b678aa405a89c..ef3a217ecdbf2 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -154,7 +154,7 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", self_ty.sty); match self_ty.sty { - ty::TyClosure(closure_def_id, substs, _) => { + ty::TyClosure(closure_def_id, ref substs) => { let closure_typer = selcx.closure_typer(); let closure_type = closure_typer.closure_type(closure_def_id, substs); let ty::Binder((_, ret_type)) = diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index af41e205aec66..c2c2ceb0b033d 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -201,7 +201,7 @@ enum SelectionCandidate<'tcx> { /// Implementation of a `Fn`-family trait by one of the /// anonymous types generated for a `||` expression. - ClosureCandidate(/* closure */ ast::DefId, &'tcx Substs<'tcx>, &'tcx Vec>), + ClosureCandidate(/* closure */ ast::DefId, &'tcx ty::ClosureSubsts<'tcx>), /// Implementation of a `Fn`-family trait by one of the anonymous /// types generated for a fn pointer type (e.g., `fn(int)->int`) @@ -348,7 +348,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // lifetimes can appear inside the self-type. let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.sty { - ty::TyClosure(id, ref substs, _) => (id, substs.clone()), + ty::TyClosure(id, ref substs) => (id, substs), _ => { return; } }; assert!(!substs.has_escaping_regions()); @@ -1142,8 +1142,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs, upvar_tys) = match self_ty.sty { - ty::TyClosure(id, substs, ref upvar_tys) => (id, substs, upvar_tys), + let (closure_def_id, substs) = match self_ty.sty { + ty::TyClosure(id, ref substs) => (id, substs), ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); candidates.ambiguous = true; @@ -1161,7 +1161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(closure_kind) => { debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate(closure_def_id, substs, upvar_tys)); + candidates.vec.push(ClosureCandidate(closure_def_id, substs)); } } None => { @@ -1703,7 +1703,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet ty::TyTuple(ref tys) => ok_if(tys.clone()), - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { // FIXME -- This case is tricky. In the case of by-ref // closures particularly, we need the results of // inference to decide how to reflect the type of each @@ -1865,7 +1865,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(tys.clone()) } - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); // TODO @@ -2015,10 +2015,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableImpl(vtable_impl)) } - ClosureCandidate(closure_def_id, substs, upvar_tys) => { + ClosureCandidate(closure_def_id, substs) => { let vtable_closure = - try!(self.confirm_closure_candidate(obligation, closure_def_id, - &substs, upvar_tys)); + try!(self.confirm_closure_candidate(obligation, closure_def_id, substs)); Ok(VtableClosure(vtable_closure)) } @@ -2367,8 +2366,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_closure_candidate(&mut self, obligation: &TraitObligation<'tcx>, closure_def_id: ast::DefId, - substs: &Substs<'tcx>, - upvar_tys: &'tcx Vec>) + substs: &ty::ClosureSubsts<'tcx>) -> Result>, SelectionError<'tcx>> { @@ -2394,7 +2392,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableClosureData { closure_def_id: closure_def_id, substs: substs.clone(), - upvar_tys: upvar_tys.clone(), nested: obligations }) } @@ -2856,7 +2853,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn closure_trait_ref_unnormalized(&mut self, obligation: &TraitObligation<'tcx>, closure_def_id: ast::DefId, - substs: &Substs<'tcx>) + substs: &ty::ClosureSubsts<'tcx>) -> ty::PolyTraitRef<'tcx> { let closure_type = self.infcx.closure_type(closure_def_id, substs); @@ -2878,7 +2875,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn closure_trait_ref(&mut self, obligation: &TraitObligation<'tcx>, closure_def_id: ast::DefId, - substs: &Substs<'tcx>) + substs: &ty::ClosureSubsts<'tcx>) -> Normalized<'tcx, ty::PolyTraitRef<'tcx>> { let trait_ref = self.closure_trait_ref_unnormalized( diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 17d55737114fb..5528472d79313 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1767,7 +1767,7 @@ pub enum TypeVariants<'tcx> { /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. - TyClosure(DefId, &'tcx Substs<'tcx>, Vec>), + TyClosure(DefId, Box>), /// A tuple type. For example, `(i32, bool)`. TyTuple(Vec>), @@ -1787,6 +1787,93 @@ pub enum TypeVariants<'tcx> { TyError, } +/// A closure can be modeled as a struct that looks like: +/// +/// struct Closure<'l0...'li, T0...Tj, U0...Uk> { +/// upvar0: U0, +/// ... +/// upvark: Uk +/// } +/// +/// where 'l0...'li and T0...Tj are the lifetime and type parameters +/// in scope on the function that defined the closure, and U0...Uk are +/// type parameters representing the types of its upvars (borrowed, if +/// appropriate). +/// +/// So, for example, given this function: +/// +/// fn foo<'a, T>(data: &'a mut T) { +/// do(|| data.count += 1) +/// } +/// +/// the type of the closure would be something like: +/// +/// struct Closure<'a, T, U0> { +/// data: U0 +/// } +/// +/// Note that the type of the upvar is not specified in the struct. +/// You may wonder how the impl would then be able to use the upvar, +/// if it doesn't know it's type? The answer is that the impl is +/// (conceptually) not fully generic over Closure but rather tied to +/// instances with the expected upvar types: +/// +/// impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> { +/// ... +/// } +/// +/// You can see that the *impl* fully specified the type of the upvar +/// and thus knows full well that `data` has type `&'b mut &'a mut T`. +/// (Here, I am assuming that `data` is mut-borrowed.) +/// +/// Now, the last question you may ask is: Why include the upvar types +/// as extra type parameters? The reason for this design is that the +/// upvar types can reference lifetimes that are internal to the +/// creating function. In my example above, for example, the lifetime +/// `'b` represents the extent of the closure itself; this is some +/// subset of `foo`, probably just the extent of the call to the to +/// `do()`. If we just had the lifetime/type parameters from the +/// enclosing function, we couldn't name this lifetime `'b`. Note that +/// there can also be lifetimes in the types of the upvars themselves, +/// if one of them happens to be a reference to something that the +/// creating fn owns. +/// +/// OK, you say, so why not create a more minimal set of parameters +/// that just includes the extra lifetime parameters? The answer is +/// primarily that it would be hard --- we don't know at the time when +/// we create the closure type what the full types of the upvars are, +/// nor do we know which are borrowed and which are not. In this +/// design, we can just supply a fresh type parameter and figure that +/// out later. +/// +/// All right, you say, but why include the type parameters from the +/// original function then? The answer is that trans may need them +/// when monomorphizing, and they may not appear in the upvars. A +/// closure could capture no variables but still make use of some +/// in-scope type parameter with a bound (e.g., if our example above +/// had an extra `U: Default`, and the closure called `U::default()`). +/// +/// There is another reason. This design (implicitly) prohibits +/// closures from capturing themselves (except via a trait +/// object). This simplifies closure inference considerably, since it +/// means that when we infer the kind of a closure or its upvars, we +/// don't have to handles cycles where the decisions we make wind up +/// for closure C wind up influencing the decisions we ought to make +/// for closure C (which would then require fixed point iteration to +/// handle). Plus it fixes an ICE. :P +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ClosureSubsts<'tcx> { + /// Lifetime and type parameters from the enclosing function. + /// These are separated out because trans wants to pass them around + /// when monomorphizing. + pub func_substs: &'tcx Substs<'tcx>, + + /// The types of the upvars. The list parallels the freevars and + /// `upvar_borrows` lists. These are kept distinct so that we can + /// easily index into them. + pub upvar_tys: Vec> +} + #[derive(Clone, PartialEq, Eq, Hash)] pub struct TraitTy<'tcx> { pub principal: ty::PolyTraitRef<'tcx>, @@ -3214,11 +3301,11 @@ impl FlagComputation { } } - &TyClosure(_, substs, ref tys) => { + &TyClosure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - self.add_substs(substs); - self.add_tys(tys); + self.add_substs(&substs.func_substs); + self.add_tys(&substs.upvar_tys); } &TyInfer(_) => { @@ -3462,10 +3549,10 @@ impl<'tcx> ctxt<'tcx> { pub fn closure_type(&self, def_id: ast::DefId, - substs: &subst::Substs<'tcx>) + substs: &ClosureSubsts<'tcx>) -> ty::ClosureTy<'tcx> { - self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, substs) + self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs) } pub fn type_parameter_def(&self, @@ -3665,7 +3752,17 @@ impl<'tcx> ctxt<'tcx> { substs: &'tcx Substs<'tcx>, tys: Vec>) -> Ty<'tcx> { - self.mk_ty(TyClosure(closure_id, substs, tys)) + self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts { + func_substs: substs, + upvar_tys: tys + })) + } + + pub fn mk_closure_from_closure_substs(&self, + closure_id: ast::DefId, + closure_substs: Box>) + -> Ty<'tcx> { + self.mk_ty(TyClosure(closure_id, closure_substs)) } pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> { @@ -3932,7 +4029,7 @@ impl<'tcx> TyS<'tcx> { TyTrait(ref tt) => Some(tt.principal_def_id()), TyStruct(id, _) | TyEnum(id, _) | - TyClosure(id, _, _) => Some(id), + TyClosure(id, _) => Some(id), _ => None } } @@ -4150,7 +4247,8 @@ impl<'tcx> TyS<'tcx> { apply_lang_items(cx, did, res) } - TyClosure(did, substs, _) => { + TyClosure(did, ref substs) => { + // TODO 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(); @@ -5911,9 +6009,9 @@ impl<'tcx> ctxt<'tcx> { // Returns a list of `ClosureUpvar`s for each upvar. pub fn closure_upvars<'a>(typer: &infer::InferCtxt<'a, 'tcx>, - closure_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> + closure_id: ast::DefId, + substs: &ClosureSubsts<'tcx>) + -> Option>> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the @@ -5932,7 +6030,7 @@ impl<'tcx> ctxt<'tcx> { Ok(t) => { t } Err(()) => { return None; } }; - let freevar_ty = freevar_ty.subst(tcx, substs); + let freevar_ty = freevar_ty.subst(tcx, &substs.func_substs); let upvar_id = ty::UpvarId { var_id: freevar_def_id.node, @@ -6382,7 +6480,7 @@ impl<'tcx> ctxt<'tcx> { } TyInfer(_) => unreachable!(), TyError => byte!(21), - TyClosure(d, _, _) => { + TyClosure(d, _) => { byte!(22); did(state, d); } @@ -6763,6 +6861,13 @@ impl<'tcx> RegionEscape for Substs<'tcx> { } } +impl<'tcx> RegionEscape for ClosureSubsts<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.func_substs.has_regions_escaping_depth(depth) || + self.upvar_tys.iter().any(|t| t.has_regions_escaping_depth(depth)) + } +} + impl RegionEscape for Vec { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.iter().any(|t| t.has_regions_escaping_depth(depth)) @@ -7106,6 +7211,15 @@ impl<'tcx> HasTypeFlags for BareFnTy<'tcx> { } } +impl<'tcx> HasTypeFlags for ClosureSubsts<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.func_substs.has_type_flags(flags) || + self.upvar_tys.iter().any(|t| t.has_type_flags(flags)) + } +} + + + impl<'tcx> fmt::Debug for ClosureTy<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ClosureTy({},{:?},{})", diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 87b5fcbd28e90..b6bb82ad7b15b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -296,6 +296,16 @@ impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::ClosureSubsts<'tcx> { + let func_substs = self.func_substs.fold_with(folder); + ty::ClosureSubsts { + func_substs: folder.tcx().mk_substs(func_substs), + upvar_tys: self.upvar_tys.fold_with(folder), + } + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { fn fold_with>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> { ty::ItemSubsts { @@ -450,7 +460,6 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureDa closure_def_id: self.closure_def_id, substs: self.substs.fold_with(folder), nested: self.nested.fold_with(folder), - upvar_tys: self.upvar_tys.fold_with(folder), } } } @@ -603,10 +612,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, let substs = substs.fold_with(this); ty::TyStruct(did, this.tcx().mk_substs(substs)) } - ty::TyClosure(did, ref substs, ref tys) => { + ty::TyClosure(did, ref substs) => { let s = substs.fold_with(this); - let tys = tys.fold_with(this); - ty::TyClosure(did, this.tcx().mk_substs(s), tys) + ty::TyClosure(did, s) } ty::TyProjection(ref data) => { ty::TyProjection(data.fold_with(this)) diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs index 33cddc978d9bb..f8678b4d8e3bd 100644 --- a/src/librustc/middle/ty_relate/mod.rs +++ b/src/librustc/middle/ty_relate/mod.rs @@ -506,16 +506,15 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, Ok(tcx.mk_struct(a_id, tcx.mk_substs(substs))) } - (&ty::TyClosure(a_id, a_substs, ref a_tys), - &ty::TyClosure(b_id, b_substs, ref b_tys)) + (&ty::TyClosure(a_id, ref a_substs), + &ty::TyClosure(b_id, ref b_substs)) if a_id == b_id => { // All TyClosure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. - let substs = try!(relate_substs(relation, None, a_substs, b_substs)); - let tys = try!(relation.relate_zip(a_tys, b_tys)); - Ok(tcx.mk_closure(a_id, tcx.mk_substs(substs), tys)) + let substs = try!(relation.relate(a_substs, b_substs)); + Ok(tcx.mk_closure_from_closure_substs(a_id, substs)) } (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => @@ -588,6 +587,20 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, } } +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ClosureSubsts<'tcx> { + fn relate(relation: &mut R, + a: &ty::ClosureSubsts<'tcx>, + b: &ty::ClosureSubsts<'tcx>) + -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let func_substs = try!(relate_substs(relation, None, a.func_substs, b.func_substs)); + let upvar_tys = try!(relation.relate_zip(&a.upvar_tys, &b.upvar_tys)); + Ok(ty::ClosureSubsts { func_substs: relation.tcx().mk_substs(func_substs), + upvar_tys: upvar_tys }) + } +} + impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region { fn relate(relation: &mut R, a: &ty::Region, diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 97f3bd1297197..81cad4486904b 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -91,9 +91,9 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyStruct(_, ref substs) => { push_reversed(stack, substs.types.as_slice()); } - ty::TyClosure(_, ref substs, ref tys) => { - push_reversed(stack, substs.types.as_slice()); - push_reversed(stack, tys); + ty::TyClosure(_, ref substs) => { + push_reversed(stack, substs.func_substs.types.as_slice()); + push_reversed(stack, &substs.upvar_tys); } ty::TyTuple(ref ts) => { push_reversed(stack, ts); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d6696e392bcff..d24fa5cef0349 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -662,11 +662,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyTrait(ref data) => write!(f, "{}", data), ty::TyProjection(ref data) => write!(f, "{}", data), TyStr => write!(f, "str"), - TyClosure(ref did, substs, _) => ty::tls::with(|tcx| { + TyClosure(ref did, ref substs) => ty::tls::with(|tcx| { try!(write!(f, "[closure")); + + // TODO consider changing this to print out the upvar types instead + let closure_tys = &tcx.tables.borrow().closure_tys; try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| { - tcx.lift(&substs).map(|substs| sig.subst(tcx, substs)) + tcx.lift(&substs.func_substs).map(|substs| sig.subst(tcx, substs)) }).map(|sig| { fn_sig(f, &sig.0.inputs, false, sig.0.output) }).unwrap_or_else(|| { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 331bcaa8da89b..6289d50588104 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2529,7 +2529,7 @@ impl LintPass for DropWithReprExtern { match dtor_self_type.sty { ty::TyEnum(self_type_did, _) | ty::TyStruct(self_type_did, _) | - ty::TyClosure(self_type_did, _, _) => { + ty::TyClosure(self_type_did, _) => { let hints = ctx.tcx.lookup_repr_hints(self_type_did); if hints.iter().any(|attr| *attr == attr::ReprExtern) && ctx.tcx.ty_dtor(self_type_did).has_drop_flag() { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 985ef2d7b14fc..b51a3d4b2a081 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -221,7 +221,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor)) } - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); @@ -441,7 +441,7 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Perhaps one of the upvars of this struct is non-zero // Let's recurse and find out! - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 03e7d9e3aa285..62b03c9fb0f1f 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -145,7 +145,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx let function_type; let (fn_sig, abi, env_ty) = match fn_type.sty { ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None), - ty::TyClosure(closure_did, substs, _) => { + ty::TyClosure(closure_did, ref substs) => { let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); function_type = infcx.closure_type(closure_did, substs); let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 678b5063816c7..e18fc6c5da2be 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -470,7 +470,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } }) } - ty::TyClosure(def_id, substs, _) => { // TODO + ty::TyClosure(def_id, ref substs) => { // TODO let repr = adt::represent_type(cx.ccx(), t); let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let upvars = infcx.closure_upvars(def_id, substs).unwrap(); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 7900000d3a9df..0f75c1f8ab65a 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -32,7 +32,6 @@ use trans::build::*; use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; -use trans::closure; use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext, ExprOrMethodCall, FunctionContext, MethodCallKey}; use trans::consts; @@ -446,12 +445,6 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( } }; - // If this is a closure, redirect to it. - match closure::get_or_create_declaration_if_closure(ccx, def_id, substs) { - None => {} - Some(llfn) => return llfn, - } - // Check whether this fn has an inlined copy and, if so, redirect // def_id to the local id of the inlined copy. let def_id = inline::maybe_instantiate_inline(ccx, def_id); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index defa0a1d898bf..b05bc7e5855e8 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -12,7 +12,6 @@ use arena::TypedArena; use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_params}; use middle::infer; -use middle::ty::Ty; use trans::adt; use trans::attributes; use trans::base::*; @@ -24,10 +23,9 @@ use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; use trans::debuginfo::{self, DebugLoc}; use trans::declare; use trans::expr; -use trans::monomorphize::{self, MonoId}; +use trans::monomorphize::{MonoId}; use trans::type_of::*; use middle::ty; -use middle::subst::Substs; use session::config::FullDebugInfo; use syntax::abi::RustCall; @@ -127,47 +125,32 @@ impl<'a> ClosureEnv<'a> { /// Returns the LLVM function declaration for a closure, creating it if /// necessary. If the ID does not correspond to a closure ID, returns None. -pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option> { - if !ccx.tcx().tables.borrow().closure_kinds.contains_key(&closure_id) { - // Not a closure. - return None - } - - let function_type = ccx.tcx().node_id_to_type(closure_id.node); - let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type); - +pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + closure_id: ast::DefId, + substs: &ty::ClosureSubsts<'tcx>) + -> ValueRef { // Normalize type so differences in regions and typedefs don't cause // duplicate declarations - let function_type = erase_regions(ccx.tcx(), &function_type); - let params = match function_type.sty { - ty::TyClosure(_, substs, _) => &substs.types, - _ => unreachable!() - }; + let substs = erase_regions(ccx.tcx(), substs); let mono_id = MonoId { def: closure_id, - params: params + params: &substs.func_substs.types }; - match ccx.closure_vals().borrow().get(&mono_id) { - Some(&llfn) => { - debug!("get_or_create_declaration_if_closure(): found closure {:?}: {:?}", - mono_id, ccx.tn().val_to_string(llfn)); - return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue))) - } - None => {} + if let Some(&llfn) = ccx.closure_vals().borrow().get(&mono_id) { + debug!("get_or_create_declaration_if_closure(): found closure {:?}: {:?}", + mono_id, ccx.tn().val_to_string(llfn)); + return llfn; } let symbol = ccx.tcx().map.with_path(closure_id.node, |path| { mangle_internal_name_by_path_and_seq(path, "closure") }); - // Currently there’s only a single user of - // get_or_create_declaration_if_closure and it unconditionally defines the - // function, therefore we use define_* here. - let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type); + let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs)); + let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", symbol)); + }); // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); @@ -179,7 +162,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc ccx.tn().val_to_string(llfn)); ccx.closure_vals().borrow_mut().insert(mono_id, llfn); - Some(Datum::new(llfn, function_type, Rvalue::new(ByValue))) + llfn } pub enum Dest<'a, 'tcx: 'a> { @@ -191,9 +174,11 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, id: ast::NodeId, - param_substs: &'tcx Substs<'tcx>) + closure_substs: &'tcx ty::ClosureSubsts<'tcx>) -> Option> { + let param_substs = closure_substs.func_substs; + let ccx = match dest { Dest::SaveIn(bcx, _) => bcx.ccx(), Dest::Ignore(ccx) => ccx @@ -204,10 +189,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, debug!("trans_closure_expr()"); let closure_id = ast_util::local_def(id); - let llfn = get_or_create_declaration_if_closure( - ccx, - closure_id, - param_substs).unwrap(); + let llfn = get_or_create_closure_declaration(ccx, closure_id, closure_substs); // Get the type of this closure. Use the current `param_substs` as // the closure substitutions. This makes sense because the closure @@ -216,7 +198,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // of the closure expression. let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); - let function_type = infcx.closure_type(closure_id, param_substs); + let function_type = infcx.closure_type(closure_id, closure_substs); let freevars: Vec = tcx.with_freevars(id, |fv| fv.iter().cloned().collect()); @@ -226,7 +208,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, trans_closure(ccx, decl, body, - llfn.val, + llfn, param_substs, id, &[], @@ -269,20 +251,12 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: ast::DefId, - substs: Substs<'tcx>, - upvar_tys: Vec>, - node: ExprOrMethodCall, - param_substs: &'tcx Substs<'tcx>, + substs: ty::ClosureSubsts<'tcx>, trait_closure_kind: ty::ClosureKind) -> ValueRef { - // The substitutions should have no type parameters remaining - // after passing through fulfill_obligation - let llfn = callee::trans_fn_ref_with_substs(ccx, - closure_def_id, - node, - param_substs, - substs.clone()).val; + // If this is a closure, redirect to it. + let llfn = get_or_create_closure_declaration(ccx, closure_def_id, &substs); // If the closure is a Fn closure, but a FnOnce is needed (etc), // then adapt the self type @@ -290,7 +264,6 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, trans_closure_adapter_shim(ccx, closure_def_id, substs, - upvar_tys, closure_kind, trait_closure_kind, llfn) @@ -299,8 +272,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, fn trans_closure_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: ast::DefId, - substs: Substs<'tcx>, - upvar_tys: Vec>, + substs: ty::ClosureSubsts<'tcx>, llfn_closure_kind: ty::ClosureKind, trait_closure_kind: ty::ClosureKind, llfn: ValueRef) @@ -339,7 +311,7 @@ fn trans_closure_adapter_shim<'a, 'tcx>( // fn call_once(mut self, ...) { call_mut(&mut self, ...) } // // These are both the same at trans time. - trans_fn_once_adapter_shim(ccx, closure_def_id, substs, upvar_tys, llfn) + trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn) } _ => { tcx.sess.bug(&format!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", @@ -352,8 +324,7 @@ fn trans_closure_adapter_shim<'a, 'tcx>( fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: ast::DefId, - substs: Substs<'tcx>, - upvar_tys: Vec>, + substs: ty::ClosureSubsts<'tcx>, llreffn: ValueRef) -> ValueRef { @@ -367,12 +338,11 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Find a version of the closure type. Substitute static for the // region since it doesn't really matter. - let substs = tcx.mk_substs(substs); - let closure_ty = tcx.mk_closure(closure_def_id, substs, upvar_tys); + let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, Box::new(substs.clone())); let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), closure_ty); // Make a version with the type of by-ref closure. - let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, substs); + let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, &substs); sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, @@ -402,7 +372,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( ast::DUMMY_NODE_ID, false, sig.output, - substs, + substs.func_substs, None, &block_arena); let mut bcx = init_function(&fcx, false, sig.output); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 302ef68bddc7d..deab11332c809 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -882,11 +882,16 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }, ast::ExprClosure(_, ref decl, ref body) => { - closure::trans_closure_expr(closure::Dest::Ignore(cx), - decl, - body, - e.id, - param_substs); + match ety.sty { + ty::TyClosure(_, ref substs) => { + closure::trans_closure_expr(closure::Dest::Ignore(cx), decl, + body, e.id, substs); + } + _ => + cx.sess().span_bug( + e.span, + &format!("bad type for closure expr: {:?}", ety)) + } C_null(type_of::type_of(cx, ety)) }, _ => cx.sess().span_bug(e.span, diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index d0c6c0ab308c4..66772e67755db 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -287,7 +287,7 @@ impl<'tcx> TypeMap<'tcx> { } } }, - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let closure_ty = infcx.closure_type(def_id, substs); self.get_unique_type_id_of_closure_type(cx, @@ -811,7 +811,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) } - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); let upvars = infcx.closure_upvars(def_id, substs).unwrap(); let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index a641302e53fab..0c77e74be38aa 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -116,7 +116,7 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, ty::TyBareFn(_, ref f) => { (&f.sig, f.abi, None) } - ty::TyClosure(closure_did, substs, _) => { + ty::TyClosure(closure_did, ref substs) => { let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); function_type = infcx.closure_type(closure_did, substs); let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index f7ace78512013..962803932b88b 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1146,8 +1146,14 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest), Ignore => closure::Dest::Ignore(bcx.ccx()) }; - closure::trans_closure_expr(dest, decl, body, expr.id, bcx.fcx.param_substs) - .unwrap_or(bcx) + let substs = match expr_ty(bcx, expr).sty { + ty::TyClosure(_, ref substs) => substs, + ref t => + bcx.tcx().sess.span_bug( + expr.span, + &format!("closure expr without closure type: {:?}", t)), + }; + closure::trans_closure_expr(dest, decl, body, expr.id, substs).unwrap_or(bcx) } ast::ExprCall(ref f, ref args) => { if bcx.tcx().is_method_call(expr.id) { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index cf2a226db41eb..4a549d9c24cda 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -341,9 +341,6 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llfn = closure::trans_closure_method(bcx.ccx(), vtable_closure.closure_def_id, vtable_closure.substs, - vtable_closure.upvar_tys, - MethodCallKey(method_call), - bcx.fcx.param_substs, trait_closure_kind); Callee { bcx: bcx, @@ -642,15 +639,11 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, traits::VtableClosureData { closure_def_id, substs, - upvar_tys, nested: _ }) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); let llfn = closure::trans_closure_method(ccx, closure_def_id, substs, - upvar_tys, - ExprId(0), - param_substs, trait_closure_kind); vec![llfn].into_iter() } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 955a301340519..4cca3b7582bfb 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -131,7 +131,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return Some(CallStep::Builtin); } - ty::TyClosure(def_id, substs, _) => { + ty::TyClosure(def_id, ref substs) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); // Check whether this is a call to a closure where we diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index f37177684d552..38207354792ae 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -41,8 +41,7 @@ pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), let dtor_predicates = tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyEnum(self_type_did, self_to_impl_substs) | - ty::TyStruct(self_type_did, self_to_impl_substs) | - ty::TyClosure(self_type_did, self_to_impl_substs, _) => { + ty::TyStruct(self_type_did, self_to_impl_substs) => { try!(ensure_drop_params_and_item_params_correspond(tcx, drop_impl_did, dtor_generics, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8b9871428c4d1..a960123efc6b8 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -288,7 +288,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } ty::TyEnum(did, _) | ty::TyStruct(did, _) | - ty::TyClosure(did, _, _) => { + ty::TyClosure(did, _) => { self.assemble_inherent_impl_candidates_for_type(did); } ty::TyBox(_) => { @@ -711,7 +711,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let steps = self.steps.clone(); for step in steps.iter() { let closure_def_id = match step.self_ty.sty { - ty::TyClosure(a, _, _) => a, + ty::TyClosure(a, _) => a, _ => continue, }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 1c21813fc63bd..ba89908bbe7e1 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -89,7 +89,6 @@ use middle::free_region::FreeRegionMap; use middle::implicator; use middle::mem_categorization as mc; use middle::region::CodeExtent; -use middle::subst::Substs; use middle::traits; use middle::ty::{self, ReScope, Ty, MethodCall, HasTypeFlags}; use middle::infer::{self, GenericKind}; @@ -1444,7 +1443,7 @@ fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region, def_id: ast::DefId, - substs: &'tcx Substs<'tcx>) { + substs: &'tcx ty::ClosureSubsts<'tcx>) { debug!("closure_must_outlive(region={:?}, def_id={:?}, substs={:?})", region, def_id, substs); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 0878ca1c29562..2b800bd9a441f 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { match self_type.ty.sty { ty::TyEnum(type_def_id, _) | ty::TyStruct(type_def_id, _) | - ty::TyClosure(type_def_id, _, _) => { + ty::TyClosure(type_def_id, _) => { tcx.destructor_for_type .borrow_mut() .insert(type_def_id, method_def_id.def_id()); From 6b49f4ded7c92da2323043bcda59886c881023e9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Jul 2015 08:20:23 -0400 Subject: [PATCH 03/10] Run the analysis process only once per closure, on the way up the tree. This was the intention before but silly coding caused it to run twice if there are nested closures. --- src/librustc_typeck/check/upvar.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index c7f084e27cda0..20db3b69bd15e 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -183,9 +183,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { * Analysis starting point. */ - self.visit_block(body); + debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id); - debug!("analyzing closure `{}` with fn body id `{}`", id, body.id); let mut euv = euv::ExprUseVisitor::new(self, self.fcx.infcx()); euv.walk_fn(decl, body); @@ -485,8 +484,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> { // ignore nested fn items } visit::FkFnBlock => { - self.analyze_closure(id, decl, body); visit::walk_fn(self, fn_kind, decl, body, span); + self.analyze_closure(id, span, decl, body); } } } From 4172c8237be8f334d613178645d8143d644a9a11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Jul 2015 08:21:11 -0400 Subject: [PATCH 04/10] Add some debugging to help identify when errors get reported. --- src/librustc/middle/expr_use_visitor.rs | 5 ++++- src/librustc/middle/mem_categorization.rs | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 54fc2daff2b8e..1df8b0ecc33b7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -256,7 +256,10 @@ macro_rules! return_if_err { ($inp: expr) => ( match $inp { Ok(v) => v, - Err(()) => return + Err(()) => { + debug!("mc reported err"); + return + } } ) } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bf47396bb9f65..ee7079bb47d59 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -367,7 +367,13 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { } fn expr_ty(&self, expr: &ast::Expr) -> McResult> { - self.typer.node_ty(expr.id) + match self.typer.node_ty(expr.id) { + Ok(t) => Ok(t), + Err(()) => { + debug!("expr_ty({:?}) yielded Err", expr); + Err(()) + } + } } fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { From a5516971342ed8fa9ddfb0a05a73c27c180125d1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Jul 2015 08:21:24 -0400 Subject: [PATCH 05/10] Don't be so eager to call unresolved inference variables an error. MC is being used now before the final regionck stage and in some cases SOME amount of unresolved inference is OK. In fact, we could probably just allow inference variables as well with only minimal pain. --- src/librustc/middle/infer/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index e6cea4d1b6ac0..48042c152b890 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1162,7 +1162,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// these unconstrained type variables. fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { let ty = self.resolve_type_vars_if_possible(t); - if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) } + if ty.references_error() { + debug!("resolve_type_vars_or_error: error from {:?}", ty); + Err(()) + } else if ty.is_ty_var() { + debug!("resolve_type_vars_or_error: error from {:?}", ty); + Err(()) + } else { + Ok(ty) + } } pub fn fully_resolve>(&self, value: &T) -> FixupResult { From 7ba288dced2d47c53a826d7f46ac6e07a37e187e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Jul 2015 08:22:03 -0400 Subject: [PATCH 06/10] 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. --- src/librustc/middle/free_region.rs | 1 - src/librustc/middle/implicator.rs | 61 ++++++++- src/librustc/middle/infer/mod.rs | 14 -- src/librustc/middle/traits/select.rs | 87 ++++-------- src/librustc/middle/ty.rs | 64 +-------- src/librustc/util/ppaux.rs | 38 ++++-- src/librustc_trans/trans/adt.rs | 16 +-- src/librustc_trans/trans/base.rs | 9 +- src/librustc_typeck/check/closure.rs | 29 ++-- src/librustc_typeck/check/regionck.rs | 21 --- src/librustc_typeck/check/upvar.rs | 126 +++++++++++------- .../regions-proc-bound-capture.rs | 2 +- 12 files changed, 215 insertions(+), 253 deletions(-) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index d902cb07494e3..102cd001a296a 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -40,7 +40,6 @@ impl FreeRegionMap { self.relate_free_regions(free_a, free_b); } Implication::RegionSubRegion(..) | - Implication::RegionSubClosure(..) | Implication::RegionSubGeneric(..) | Implication::Predicate(..) => { } diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index 8fba98bead479..a129039002c5f 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -28,7 +28,6 @@ use util::nodemap::FnvHashSet; pub enum Implication<'tcx> { RegionSubRegion(Option>, ty::Region, ty::Region), RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), - RegionSubClosure(Option>, ty::Region, ast::DefId, &'tcx ty::ClosureSubsts<'tcx>), Predicate(ast::DefId, ty::Predicate<'tcx>), } @@ -96,10 +95,47 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { // No borrowed content reachable here. } - ty::TyClosure(def_id, ref substs) => { - // TODO remove RegionSubClosure - let &(r_a, opt_ty) = self.stack.last().unwrap(); - self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs)); + ty::TyClosure(_, ref substs) => { + // FIXME(#27086). We do not accumulate from substs, since they + // don't represent reachable data. This means that, in + // 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) { + // } + // ``` + // + // 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) => { @@ -274,6 +310,21 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { self.out.extend(obligations); 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) { match variance { diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 48042c152b890..46cbf9351e062 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1399,20 +1399,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { closure_ty } } - - pub fn closure_upvars(&self, - def_id: ast::DefId, - substs: &ty::ClosureSubsts<'tcx>) - -> Option>> - { - 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> { diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index c2c2ceb0b033d..4061581ded8f0 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1284,22 +1284,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; } _ => { - if self.constituent_types_for_ty(self_ty).is_some() { - 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; - } + candidates.vec.push(DefaultImplCandidate(def_id.clone())) } } } @@ -1729,14 +1714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return ok_if(Vec::new()); } - // TODO - 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) - } - } + ok_if(substs.upvar_tys.clone()) } ty::TyStruct(def_id, substs) => { @@ -1819,7 +1797,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option>> { + fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { match t.sty { ty::TyUint(_) | ty::TyInt(_) | @@ -1831,7 +1809,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | ty::TyChar => { - Some(Vec::new()) + Vec::new() } ty::TyTrait(..) | @@ -1848,56 +1826,56 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::TyBox(referent_ty) => { // Box - Some(vec![referent_ty]) + vec![referent_ty] } ty::TyRawPtr(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) => { - Some(vec![element_ty]) + vec![element_ty] } ty::TyTuple(ref tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Some(tys.clone()) + tys.clone() } 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); - - // TODO - match self.infcx.closure_upvars(def_id, substs) { - Some(upvars) => { - Some(upvars.iter().map(|c| c.ty).collect()) - } - None => { - None - } - } + substs.upvar_tys.clone() } // for `PhantomData`, we pass `T` ty::TyStruct(def_id, substs) 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) => { - Some(self.tcx().struct_fields(def_id, substs).iter() - .map(|f| f.mt.ty) - .collect()) + self.tcx().struct_fields(def_id, substs) + .iter() + .map(|f| f.mt.ty) + .collect() } ty::TyEnum(def_id, substs) => { - Some(self.tcx().substd_enum_variants(def_id, substs) - .iter() - .flat_map(|variant| &variant.args) - .map(|&ty| ty) - .collect()) + self.tcx().substd_enum_variants(def_id, substs) + .iter() + .flat_map(|variant| &variant.args) + .map(|&ty| ty) + .collect() } } } @@ -2147,15 +2125,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // binder is moved below let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - match self.constituent_types_for_ty(self_ty) { - Some(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)); - } - } + let types = self.constituent_types_for_ty(self_ty); + self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)) } fn confirm_default_impl_object_candidate(&mut self, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5528472d79313..94b5e7e3a59a9 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4247,12 +4247,8 @@ impl<'tcx> TyS<'tcx> { apply_lang_items(cx, did, res) } - TyClosure(did, ref substs) => { - // TODO - 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)) + TyClosure(_, ref substs) => { + TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache)) } TyTuple(ref tys) => { @@ -6007,62 +6003,6 @@ impl<'tcx> ctxt<'tcx> { (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>> - { - // 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. pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize { let hint = UncheckedExprHint(self.types.usize); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d24fa5cef0349..fd49d0468c906 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -665,22 +665,32 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyClosure(ref did, ref substs) => ty::tls::with(|tcx| { try!(write!(f, "[closure")); - // TODO consider changing this to print out the upvar types instead - - let closure_tys = &tcx.tables.borrow().closure_tys; - try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| { - tcx.lift(&substs.func_substs).map(|substs| sig.subst(tcx, substs)) - }).map(|sig| { - fn_sig(f, &sig.0.inputs, false, sig.0.output) - }).unwrap_or_else(|| { - if did.krate == ast::LOCAL_CRATE { - try!(write!(f, " {:?}", tcx.map.span(did.node))); + if did.krate == ast::LOCAL_CRATE { + try!(write!(f, "@{:?}", tcx.map.span(did.node))); + let mut sep = " "; + try!(tcx.with_freevars(did.node, |freevars| { + for (freevar, upvar_ty) in freevars.iter().zip(&substs.upvar_tys) { + let node_id = freevar.def.local_node_id(); + try!(write!(f, + "{}{}:{}", + sep, + 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, "]") }), TyArray(ty, sz) => write!(f, "[{}; {}]", ty, sz), diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index b51a3d4b2a081..dc7e34a386f93 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -48,7 +48,6 @@ use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; use back::abi::FAT_PTR_ADDR; use middle::subst; -use middle::infer; use middle::ty::{self, Ty}; use middle::ty::Disr; 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)) } - ty::TyClosure(def_id, ref substs) => { - let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO - let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); - Univariant(mk_struct(cx, &upvar_types[..], false, t), 0) + ty::TyClosure(_, ref substs) => { + Univariant(mk_struct(cx, &substs.upvar_tys, false, t), 0) } ty::TyEnum(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 // Let's recurse and find out! - ty::TyClosure(def_id, ref substs) => { - let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); - let upvars = infcx.closure_upvars(def_id, substs).unwrap(); // TODO - let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); - - for (j, &ty) in upvar_types.iter().enumerate() { + ty::TyClosure(_, ref substs) => { + for (j, &ty) in substs.upvar_tys.iter().enumerate() { if let Some(mut fpath) = find_discr_field_candidate(tcx, ty, path.clone()) { fpath.push(j); return Some(fpath); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index e18fc6c5da2be..207251496e457 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -37,7 +37,6 @@ use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; use middle::cfg; -use middle::infer; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; 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 infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let upvars = infcx.closure_upvars(def_id, substs).unwrap(); - for (i, upvar) in upvars.iter().enumerate() { + for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { 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) => { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 71e51292a7846..cb5875ec8bcea 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -53,25 +53,26 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, opt_kind, expected_sig); - let mut fn_ty = astconv::ty_of_closure( - fcx, - ast::Unsafety::Normal, - decl, - abi::RustCall, - expected_sig); - - let freevar_tys = - fcx.tcx().with_freevars(expr.id, |fv| { - fv.iter() - .map(|_| fcx.tcx().types.bool) // TODO - .collect() - }); + let mut fn_ty = astconv::ty_of_closure(fcx, + ast::Unsafety::Normal, + decl, + abi::RustCall, + expected_sig); + + // Create type variables (for now) to represent the transformed + // types of upvars. These will be unified during the upvar + // inference phase (`upvar.rs`). + let num_upvars = fcx.tcx().with_freevars(expr.id, |fv| fv.len()); + let upvar_tys = fcx.infcx().next_ty_vars(num_upvars); + + debug!("check_closure: expr.id={:?} upvar_tys={:?}", + expr.id, upvar_tys); let closure_type = fcx.ccx.tcx.mk_closure( expr_def_id, fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()), - freevar_tys); + upvar_tys); fcx.write_ty(expr.id, closure_type); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index ba89908bbe7e1..c6f543210ad14 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -382,7 +382,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { self.region_bound_pairs.push((r_a, generic_b.clone())); } implicator::Implication::RegionSubRegion(..) | - implicator::Implication::RegionSubClosure(..) | implicator::Implication::Predicate(..) => { // In principle, we could record (and take // 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()); 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) => { let cause = traits::ObligationCause::new(origin.span(), 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>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 20db3b69bd15e..0e3fa654efaad 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -42,9 +42,10 @@ use super::FnCtxt; +use check::demand; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; -use middle::ty::{self}; +use middle::ty::{self, Ty}; use middle::infer::{InferCtxt, UpvarRegion}; use std::collections::HashSet; use syntax::ast; @@ -178,54 +179,55 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { 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. */ 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()); - euv.walk_fn(decl, body); - - // If we had not yet settled on a closure kind for this closure, - // then we should have by now. Process and remove any deferred resolutions. - // - // Interesting fact: all calls to this closure must come - // *after* its definition. Initially, I thought that some - // kind of fixed-point iteration would be required, due to the - // possibility of twisted examples like this one: - // - // ```rust - // let mut closure0 = None; - // let vec = vec!(1, 2, 3); - // - // loop { - // { - // let closure1 = || { - // match closure0.take() { - // Some(c) => { - // return c(); // (*) call to `closure0` before it is defined - // } - // None => { } - // } - // }; - // closure1(); - // } - // - // closure0 = || vec; - // } - // ``` + // Now that we've analyzed the closure, we know how each + // 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. // - // 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 + // 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). + + // Extract the type variables UV0...UVn. + let closure_substs = match self.fcx.node_ty(id).sty { + ty::TyClosure(_, ref substs) => substs, + ref t => { + self.fcx.tcx().sess.span_bug( + span, + &format!("type of closure expr {:?} is not a closure {:?}", + id, t)); + } + }; + + // Equate the type variables with the actual types. + let final_upvar_tys = self.final_upvar_tys(id); + debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", + id, closure_substs, final_upvar_tys); + for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) { + demand::eqtype(self.fcx, span, final_upvar_ty, upvar_ty); + } + + // Now we must process and remove any deferred resolutions, + // since we have a concrete closure kind. let closure_def_id = ast_util::local_def(id); if self.closures_with_inferred_kinds.contains(&id) { 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> { + // 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, cmt: mc::cmt<'tcx>, 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 self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind); - let upvar_capture_map = &mut self.fcx - .inh - .tables.borrow_mut() - .upvar_capture_map; + let upvar_capture_map = + &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map; upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue); } mc::NoteClosureEnv(upvar_id) => { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index 3c137133c9867..48b6e8b773f3b 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -18,7 +18,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(isize) + '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() { } From 37aad77ce25229454d796bc85894ae0826ac937a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Jul 2015 08:26:14 -0400 Subject: [PATCH 07/10] Add regression test for #25954 (cyclic closure type), which is now impossible. --- .../closure-referencing-itself-issue-25954.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/compile-fail/closure-referencing-itself-issue-25954.rs diff --git a/src/test/compile-fail/closure-referencing-itself-issue-25954.rs b/src/test/compile-fail/closure-referencing-itself-issue-25954.rs new file mode 100644 index 0000000000000..9357d0e761571 --- /dev/null +++ b/src/test/compile-fail/closure-referencing-itself-issue-25954.rs @@ -0,0 +1,28 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #25954: detect and reject a closure type that +// references itself. + +use std::cell::{Cell, RefCell}; + +struct A { + x: RefCell>, + b: Cell, +} + +fn main() { + let mut p = A{x: RefCell::new(None), b: Cell::new(4i32)}; + + // This is an error about types of infinite size: + let q = || p.b.set(5i32); //~ ERROR mismatched types + + *(p.x.borrow_mut()) = Some(q); +} From f8931a793346985229d7392620abea50d3e96ac5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Jul 2015 21:05:09 -0400 Subject: [PATCH 08/10] Add regression test for #25368. Fixes #25368. --- src/test/compile-fail/issue-25368.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/compile-fail/issue-25368.rs diff --git a/src/test/compile-fail/issue-25368.rs b/src/test/compile-fail/issue-25368.rs new file mode 100644 index 0000000000000..e70c00502210f --- /dev/null +++ b/src/test/compile-fail/issue-25368.rs @@ -0,0 +1,23 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::sync::mpsc::channel; +use std::thread::spawn; +use std::marker::PhantomData; + +struct Foo {foo: PhantomData} + +fn main() { + let (tx, rx) = channel(); + + spawn(move || { + tx.send(Foo{ foo: PhantomData }); //~ ERROR E0282 + }); +} From d075faa2ed2a9290a4ac114ff6e0b87c03e86b98 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Jul 2015 21:08:29 -0400 Subject: [PATCH 09/10] nits --- src/librustc/middle/implicator.rs | 2 +- src/librustc/middle/infer/mod.rs | 5 +---- src/librustc/middle/ty.rs | 8 +++----- src/librustc_trans/trans/closure.rs | 2 +- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index a129039002c5f..799d9a653ae38 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { // // 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 + // the closure type `C: 'static` (so it can be coerced // to the object type), we get the requirement that // `'a: 'static` since `'a` appears in the closure // type `C`. diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 46cbf9351e062..a54aee2436772 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1162,10 +1162,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// these unconstrained type variables. fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { let ty = self.resolve_type_vars_if_possible(t); - if ty.references_error() { - debug!("resolve_type_vars_or_error: error from {:?}", ty); - Err(()) - } else if ty.is_ty_var() { + if ty.references_error() || ty.is_ty_var() { debug!("resolve_type_vars_or_error: error from {:?}", ty); Err(()) } else { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 94b5e7e3a59a9..aa1c8bfaa904f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1857,9 +1857,9 @@ pub enum TypeVariants<'tcx> { /// closures from capturing themselves (except via a trait /// object). This simplifies closure inference considerably, since it /// means that when we infer the kind of a closure or its upvars, we -/// don't have to handles cycles where the decisions we make wind up -/// for closure C wind up influencing the decisions we ought to make -/// for closure C (which would then require fixed point iteration to +/// don't have to handle cycles where the decisions we make for +/// closure C wind up influencing the decisions we ought to make for +/// closure C (which would then require fixed point iteration to /// handle). Plus it fixes an ICE. :P #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct ClosureSubsts<'tcx> { @@ -7158,8 +7158,6 @@ impl<'tcx> HasTypeFlags for ClosureSubsts<'tcx> { } } - - impl<'tcx> fmt::Debug for ClosureTy<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ClosureTy({},{:?},{})", diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index b05bc7e5855e8..ff89d97c47b11 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -138,7 +138,7 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; if let Some(&llfn) = ccx.closure_vals().borrow().get(&mono_id) { - debug!("get_or_create_declaration_if_closure(): found closure {:?}: {:?}", + debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", mono_id, ccx.tn().val_to_string(llfn)); return llfn; } From 71d44189e04d714a64c304f00a7ebfd48150b93a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Jul 2015 04:48:32 -0400 Subject: [PATCH 10/10] minor rebase fixes --- src/librustc_trans/trans/closure.rs | 4 +--- src/librustc_trans/trans/debuginfo/metadata.rs | 8 ++------ src/librustc_trans/trans/debuginfo/mod.rs | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index ff89d97c47b11..ef5da3e40dfda 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -148,9 +148,7 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }); let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs)); - let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", symbol)); - }); + let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type); // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 66772e67755db..09495dea28686 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -811,14 +811,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) } - ty::TyClosure(def_id, ref substs) => { - let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let upvars = infcx.closure_upvars(def_id, substs).unwrap(); - let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); - + ty::TyClosure(_, ref substs) => { prepare_tuple_metadata(cx, t, - &upvar_types[..], + &substs.upvar_tys, unique_type_id, usage_site_span).finalize(cx) } diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 9ce5c457bff33..8e4e0aaa75fec 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -416,7 +416,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyBareFn(_, ref barefnty) => { (cx.tcx().erase_late_bound_regions(&barefnty.sig), barefnty.abi) } - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, ref substs) => { let closure_type = cx.tcx().closure_type(def_id, substs); (cx.tcx().erase_late_bound_regions(&closure_type.sig), closure_type.abi) }