From ca9b5664c3c4a052a044d63725239ff2e56136f4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 3 Nov 2016 22:19:33 +0200 Subject: [PATCH 1/4] rustc: move closure upvar types to the closure substs This moves closures to the (DefId, Substs) scheme like all other items, and saves a word from the size of TyS now that Substs is 2 words. --- src/librustc/infer/mod.rs | 2 +- src/librustc/lib.rs | 1 + src/librustc/traits/select.rs | 6 +-- src/librustc/ty/contents.rs | 13 ++++--- src/librustc/ty/context.rs | 7 +--- src/librustc/ty/flags.rs | 3 +- src/librustc/ty/layout.rs | 12 +++++- src/librustc/ty/mod.rs | 4 +- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 9 +---- src/librustc/ty/structural_impls.rs | 12 ++---- src/librustc/ty/sty.rs | 23 +++++++---- src/librustc/ty/subst.rs | 14 +++++++ src/librustc/ty/util.rs | 11 ++++++ src/librustc/ty/walk.rs | 3 +- src/librustc/util/ppaux.rs | 5 ++- .../borrowck/mir/elaborate_drops.rs | 8 ++-- src/librustc_metadata/encoder.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/transform/type_check.rs | 12 ++++-- src/librustc_trans/adt.rs | 4 +- src/librustc_trans/closure.rs | 7 ++-- src/librustc_trans/collector.rs | 6 +-- src/librustc_trans/common.rs | 11 +++++- src/librustc_trans/debuginfo/metadata.rs | 5 ++- src/librustc_trans/debuginfo/mod.rs | 13 +++---- src/librustc_trans/glue.rs | 4 +- src/librustc_trans/mir/mod.rs | 4 +- src/librustc_trans/trans_item.rs | 6 ++- src/librustc_typeck/check/closure.rs | 38 +++++++++++++++++-- src/librustc_typeck/check/dropck.rs | 10 ++++- src/librustc_typeck/check/upvar.rs | 8 ++-- 32 files changed, 179 insertions(+), 92 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 46074f6c1f3c8..24716c4795134 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1657,7 +1657,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let InferTables::Local(tables) = self.tables { if let Some(ty) = tables.borrow().closure_tys.get(&def_id) { - return ty.subst(self.tcx, substs.func_substs); + return ty.subst(self.tcx, substs.substs); } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fa49e5c728951..8c0d70c6d602b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -40,6 +40,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] +#![feature(unboxed_closures)] #![cfg_attr(stage0, feature(question_mark))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3944c7e09c0b8..6f6534cb2064a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1912,16 +1912,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { tys.to_vec() } - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, ref substs) => { // FIXME(#27086). We are invariant w/r/t our - // substs.func_substs, but we don't see them as + // 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" - substs.upvar_tys.to_vec() + substs.upvar_tys(def_id, self.tcx()).collect() } // for `PhantomData`, we pass `T` diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 7ed4de38be97e..9f80c2487fb2c 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -98,10 +98,11 @@ impl TypeContents { TC::OwnsOwned | (*self & TC::OwnsAll) } - pub fn union(v: &[T], mut f: F) -> TypeContents where - F: FnMut(&T) -> TypeContents, + pub fn union(v: I, mut f: F) -> TypeContents where + I: IntoIterator, + F: FnMut(T) -> TypeContents, { - v.iter().fold(TC::None, |tc, ty| tc | f(ty)) + v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) } pub fn has_dtor(&self) -> bool { @@ -215,8 +216,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } ty::TyStr => TC::None, - ty::TyClosure(_, ref substs) => { - TypeContents::union(&substs.upvar_tys, |ty| tc_ty(tcx, &ty, cache)) + ty::TyClosure(def_id, ref substs) => { + TypeContents::union( + substs.upvar_tys(def_id, tcx), + |ty| tc_ty(tcx, &ty, cache)) } ty::TyTuple(ref tys) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ac1c4fc6a1911..45450456e8a65 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1446,12 +1446,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_closure(self, closure_id: DefId, - substs: &'tcx Substs<'tcx>, - tys: &[Ty<'tcx>]) + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { - func_substs: substs, - upvar_tys: self.intern_type_list(tys) + substs: substs }) } @@ -1574,4 +1572,3 @@ impl InternIteratorElement for Result { Ok(f(&iter.collect::, _>>()?)) } } - diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 649d78f9d9e2d..2c09b89beb232 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -88,8 +88,7 @@ impl FlagComputation { &ty::TyClosure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - self.add_substs(&substs.func_substs); - self.add_tys(&substs.upvar_tys); + self.add_substs(&substs.substs); } &ty::TyInfer(infer) => { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5ce43d905ec71..5ee1c3678d675 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -631,7 +631,9 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the upvars of this closure is non-zero // Let's recurse and find out! - (_, &ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. })) | + (_, &ty::TyClosure(def_id, ref substs)) => { + Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx)) + } // Can we use one of the fields in this tuple? (_, &ty::TyTuple(tys)) => { Struct::non_zero_field_path(infcx, tys.iter().cloned()) @@ -961,7 +963,13 @@ impl<'a, 'gcx, 'tcx> Layout { } // Tuples and closures. - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) | + ty::TyClosure(def_id, ref substs) => { + let mut st = Struct::new(dl, false); + let tys = substs.upvar_tys(def_id, tcx); + st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?; + Univariant { variant: st, non_zero: false } + } + ty::TyTuple(tys) => { let mut st = Struct::new(dl, false); st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3db705140411a..1de54f49a5522 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2544,12 +2544,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // tables by typeck; else, it will be retreived from // the external crate metadata. if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) { - return ty.subst(self, substs.func_substs); + return ty.subst(self, substs.substs); } let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id); self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone()); - ty.subst(self, substs.func_substs) + ty.subst(self, substs.substs) } /// Given the def_id of an impl, return the def_id of the trait it implements. diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 51feab9d40c9a..e3d13f593954f 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // in the `subtys` iterator (e.g., when encountering a // projection). match ty.sty { - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, 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 @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // what func/type parameters are used and unused, // taking into consideration UFCS and so forth. - for &upvar_ty in substs.upvar_tys { + for upvar_ty in substs.upvar_tys(def_id, *self) { self.compute_components(upvar_ty, out); } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cb90e6392cf03..2a01bad33c52e 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -534,13 +534,8 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?; - assert_eq!(a.upvar_tys.len(), b.upvar_tys.len()); - Ok(ty::ClosureSubsts { - func_substs: substs, - upvar_tys: relation.tcx().mk_type_list( - a.upvar_tys.iter().zip(b.upvar_tys).map(|(a, b)| relation.relate(a, b)))? - }) + let substs = relate_substs(relation, None, a.substs, b.substs)?; + Ok(ty::ClosureSubsts { substs: substs }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 282cb9f80f51e..e73be23a42c76 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -198,11 +198,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { type Lifted = ty::ClosureSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.func_substs, self.upvar_tys)).map(|(substs, upvar_tys)| { - ty::ClosureSubsts { - func_substs: substs, - upvar_tys: upvar_tys - } + tcx.lift(&self.substs).map(|substs| { + ty::ClosureSubsts { substs: substs } }) } } @@ -654,13 +651,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ClosureSubsts { - func_substs: self.func_substs.fold_with(folder), - upvar_tys: self.upvar_tys.fold_with(folder), + substs: self.substs.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor) + self.substs.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7d209093ec776..56466d5968298 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -11,6 +11,7 @@ //! This module contains TypeVariants and its major components use hir::def_id::DefId; + use middle::region; use ty::subst::Substs; use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable}; @@ -254,15 +255,23 @@ pub enum TypeVariants<'tcx> { /// handle). Plus it fixes an ICE. :P #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { - /// Lifetime and type parameters from the enclosing function. + /// Lifetime and type parameters from the enclosing function, + /// concatenated with the types of the upvars. + /// /// These are separated out because trans wants to pass them around /// when monomorphizing. - pub func_substs: &'tcx Substs<'tcx>, + pub 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: &'tcx Slice> +impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { + #[inline] + pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> + impl Iterator> + 'tcx + { + let generics = tcx.item_generics(def_id); + self.substs[self.substs.len()-generics.own_count()..].iter().map( + |t| t.as_type().expect("unexpected region in upvars")) + } } #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -1234,7 +1243,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { substs.regions().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions().collect() + substs.substs.regions().collect() } TyProjection(ref data) => { data.trait_ref.substs.regions().collect() diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 15f4437ed0aaf..76d512a20b26e 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -274,6 +274,20 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let defs = tcx.item_generics(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } + + pub fn extend_with_types(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, + types: &[Ty<'tcx>]) + -> &'tcx Substs<'tcx> { + tcx.mk_substs( + self[..].iter().cloned().chain( + types.iter().map(|a| Kind::from(*a))) + ) + } + + pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>) + -> &'tcx Substs<'tcx> { + tcx.mk_substs(self.iter().take(generics.count()).cloned()) + } } impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index b1aeaeb48d144..7d3e380a3b590 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -11,6 +11,7 @@ //! misc. type-system utilities too small to deserve their own file use hir::def_id::DefId; +use hir::map::DefPathData; use infer::InferCtxt; use hir::map as ast_map; use hir::pat_util; @@ -390,6 +391,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // (e.g. calling `foo.0.clone()` of `Foo`). return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params"); } + + pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + let mut def_id = def_id; + while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { + def_id = self.parent_def_id(def_id).unwrap_or_else(|| { + bug!("closure {:?} has no parent", def_id); + }); + } + def_id + } } /// When hashing a type this ends up affecting properties like symbol names. We diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index bebdebf127a54..a6ecfd2fb7066 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -97,8 +97,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { - stack.extend(substs.func_substs.types().rev()); - stack.extend(substs.upvar_tys.iter().cloned().rev()); + stack.extend(substs.substs.types().rev()); } ty::TyTuple(ts) => { stack.extend(ts.iter().cloned().rev()); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3ed4580336aac..a63c7ba6a25ce 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -907,13 +907,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } TyStr => write!(f, "str"), TyClosure(did, substs) => ty::tls::with(|tcx| { + let upvar_tys = substs.upvar_tys(did, tcx); write!(f, "[closure")?; if let Some(node_id) = tcx.map.as_local_node_id(did) { write!(f, "@{:?}", tcx.map.span(node_id))?; let mut sep = " "; tcx.with_freevars(node_id, |freevars| { - for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) { + for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { let def_id = freevar.def.def_id(); let node_id = tcx.map.as_local_node_id(def_id).unwrap(); write!(f, @@ -930,7 +931,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { // visible in trans bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; - for (index, upvar_ty) in substs.upvar_tys.iter().enumerate() { + for (index, upvar_ty) in upvar_tys.enumerate() { write!(f, "{}{}:{}", sep, index, upvar_ty)?; sep = ", "; } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index eced5d1eb1b80..cdb19d164bf29 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,9 +709,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty::TyAdt(def, substs) => { self.open_drop_for_adt(c, def, substs) } - ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { - upvar_tys: tys, .. - }) => { + ty::TyClosure(def_id, substs) => { + let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect(); + self.open_drop_for_tuple(c, &tys) + } + ty::TyTuple(tys) => { self.open_drop_for_tuple(c, tys) } ty::TyBox(ty) => { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f169ad6648086..4d7aa43ce42db 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1059,7 +1059,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty: None, inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), - generics: None, + generics: Some(self.encode_generics(def_id)), predicates: None, ast: None, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ba0d3b49a6c1a..24c1ca574a01b 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -521,8 +521,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; let upvars = cx.tcx.with_freevars(expr.id, |freevars| { freevars.iter() - .enumerate() - .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i])) + .zip(substs.upvar_tys(def_id, cx.tcx)) + .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty)) .collect() }); ExprKind::Closure { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index ad525d2106947..79bb14b7336c1 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -274,9 +274,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } - ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { - upvar_tys: tys, .. - }) => { + ty::TyClosure(def_id, substs) => { + return match substs.upvar_tys(def_id, tcx).nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.upvar_tys(def_id, tcx).count() + }) + } + } + ty::TyTuple(tys) => { return match tys.get(field.index()) { Some(&ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index d028dd7e7b5a0..c3340281d0732 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -108,9 +108,9 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, }).collect::>() }, ty::TyTuple(fields) => fields.to_vec(), - ty::TyClosure(_, substs) => { + ty::TyClosure(def_id, substs) => { if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);} - substs.upvar_tys.to_vec() + substs.upvar_tys(def_id, cx.tcx()).collect() }, _ => bug!("{} is not a type that can have fields.", t) } diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index a1d645fb993b0..0cefc49cb425e 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -49,7 +49,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // duplicate declarations let tcx = ccx.tcx(); let substs = tcx.erase_regions(&substs); - let instance = Instance::new(closure_id, substs.func_substs); + let instance = Instance::new(closure_id, substs.substs); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", @@ -99,8 +99,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tcx = ccx.tcx(); let _icx = push_ctxt("closure::trans_closure_expr"); - let param_substs = closure_substs.func_substs; - let instance = Instance::new(closure_def_id, param_substs); + let instance = Instance::new(closure_def_id, closure_substs.substs); // If we have not done so yet, translate this closure's body if !ccx.instances().borrow().contains_key(&instance) { @@ -138,7 +137,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trans_closure(ccx, llfn, - Instance::new(closure_def_id, param_substs), + instance, &sig, Abi::RustCall); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 41071057274f1..a79719a4d2272 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let concrete_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, - &substs.func_substs); + &substs.substs); let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); let visitor = MirNeighborCollector { @@ -797,8 +797,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } } - ty::TyClosure(_, substs) => { - for upvar_ty in substs.upvar_tys { + ty::TyClosure(def_id, substs) => { + for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) { let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty); if glue::type_needs_drop(scx.tcx(), upvar_ty) { output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty))); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d238cf7bb4582..6f3a726215207 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -109,7 +109,16 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]), monomorphize::field_ty(ccx.tcx(), substs, &fields[1])]) } - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) | + ty::TyClosure(def_id, substs) => { + let mut tys = substs.upvar_tys(def_id, ccx.tcx()); + tys.next().and_then(|first_ty| tys.next().and_then(|second_ty| { + if tys.next().is_some() { + None + } else { + Some([first_ty, second_ty]) + } + })) + } ty::TyTuple(tys) => { if tys.len() != 2 { return None; diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 679e308c34542..5b9ef78ddc22e 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -574,10 +574,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) } - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, substs) => { + let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx()).collect(); prepare_tuple_metadata(cx, t, - &substs.upvar_tys, + &upvar_tys, unique_type_id, usage_site_span).finalize(cx) } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 45b8ec1dc80bb..482275d298bc0 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -25,7 +25,6 @@ use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, FlagPrototyped}; use rustc::hir::def_id::DefId; -use rustc::hir::map::DefPathData; use rustc::ty::subst::Substs; use abi::Abi; @@ -248,21 +247,19 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; // Find the enclosing function, in case this is a closure. - let mut fn_def_id = instance.def; - let mut def_key = cx.tcx().def_key(fn_def_id); + let def_key = cx.tcx().def_key(instance.def); let mut name = def_key.disambiguated_data.data.to_string(); let name_len = name.len(); - while def_key.disambiguated_data.data == DefPathData::ClosureExpr { - fn_def_id.index = def_key.parent.expect("closure without a parent?"); - def_key = cx.tcx().def_key(fn_def_id); - } + + let fn_def_id = cx.tcx().closure_base_def_id(instance.def); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. let generics = cx.tcx().item_generics(fn_def_id); + let substs = instance.substs.truncate_to(cx.tcx(), generics); let template_parameters = get_template_parameters(cx, &generics, - instance.substs, + substs, file_metadata, &mut name); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 648dd9f3e3aea..d6d4d33923f1a 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -531,8 +531,8 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let mut cx = cx; match t.sty { - ty::TyClosure(_, ref substs) => { - for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { + ty::TyClosure(def_id, substs) => { + for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() { let llupvar = adt::trans_field_ptr(cx, t, value, Disr(0), i); cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None); } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index d2adf88c91683..12b17c26cbc41 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -470,8 +470,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, } else { (arg_ty, false) }; - let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty { - &substs.upvar_tys[..] + let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty { + substs.upvar_tys(def_id, tcx) } else { bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty); }; diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 93790cc27bcaf..16bc7e212cf54 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -477,12 +477,14 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, push_unique_type_name(tcx, sig.output, output); } }, - ty::TyClosure(def_id, ref closure_substs) => { + ty::TyClosure(def_id, closure_substs) => { push_item_name(tcx, def_id, output); output.push_str("{"); output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); output.push_str("}"); - push_type_params(tcx, closure_substs.func_substs, &[], output); + let generics = tcx.item_generics(tcx.closure_base_def_id(def_id)); + let substs = closure_substs.substs.truncate_to(tcx, generics); + push_type_params(tcx, substs, &[], output); } ty::TyError | ty::TyInfer(_) | diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index af834f3f84d47..d48a129dfe1cd 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -14,10 +14,13 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; use rustc::ty::{self, ToPolyTraitRef, Ty}; +use rustc::util::common::MemoizationMap; use std::cmp; use syntax::abi::Abi; use rustc::hir; +use syntax::parse::token; + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_closure(&self, expr: &hir::Expr, @@ -48,6 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_sig: Option>) -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); + let base_def_id = self.tcx.closure_base_def_id(expr_def_id); debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, @@ -62,16 +66,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 = self.tcx.with_freevars(expr.id, |fv| fv.len()); + let base_generics = self.tcx.item_generics(base_def_id); + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = self.tcx.with_freevars(expr.id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: expr_def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + let num_upvars = upvar_decls.len(); + + self.tcx.generics.memoize(expr_def_id, || self.tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: false, + })); + let upvar_tys = self.next_ty_vars(num_upvars); debug!("check_closure: expr.id={:?} upvar_tys={:?}", expr.id, upvar_tys); - let closure_type = self.tcx.mk_closure(expr_def_id, - self.parameter_environment.free_substs, - &upvar_tys); + let closure_type = self.tcx.mk_closure( + expr_def_id, + self.parameter_environment.free_substs.extend_with_types(self.tcx, &upvar_tys) + ); let fn_sig = self.tcx .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id), diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 8657b30bf8ee1..09e1f6592c170 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -482,8 +482,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( Ok(()) } - ty::TyTuple(tys) | - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) => { + ty::TyClosure(def_id, substs) => { + for ty in substs.upvar_tys(def_id, tcx) { + iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? + } + Ok(()) + } + + ty::TyTuple(tys) => { for ty in tys { iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 2fea86cb21207..1ea47107c3b18 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -183,8 +183,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // 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, + let (def_id, closure_substs) = match self.fcx.node_ty(id).sty { + ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( span, @@ -197,7 +197,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { 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) { + for (upvar_ty, final_upvar_ty) in + closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys) + { self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); } From b6828fd1acf11272b05c32010f9071d3e8862e76 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 9 Nov 2016 20:41:03 +0200 Subject: [PATCH 2/4] rustc_typeck: register item types for closures This makes them closer to actual items and allows for more transparent treatment. --- src/librustc_metadata/encoder.rs | 2 +- src/librustc_typeck/check/closure.rs | 77 +++++++++++++++++----------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4d7aa43ce42db..778a9d185e145 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1056,7 +1056,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { stability: None, deprecation: None, - ty: None, + ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d48a129dfe1cd..3efbd6b30c220 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,7 +13,9 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; +use rustc::hir::def_id::DefId; use rustc::ty::{self, ToPolyTraitRef, Ty}; +use rustc::ty::subst::Substs; use rustc::util::common::MemoizationMap; use std::cmp; use syntax::abi::Abi; @@ -43,6 +45,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_closure(expr, expected_kind, decl, body, expected_sig) } + fn declare_closure(&self, def_id: DefId) { + let tcx = self.tcx.global_tcx(); + + tcx.generics.memoize(def_id, || { + let node_id = tcx.map.as_local_node_id(def_id).unwrap(); + let base_def_id = self.tcx.closure_base_def_id(def_id); + let base_generics = tcx.item_generics(base_def_id); + + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + + tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: false, + }) + }); + + tcx.item_types.memoize(def_id, || tcx.mk_closure(def_id, Substs::for_item( + tcx, def_id, + |def, _| tcx.mk_region(def.to_early_bound_region()), + |def, _| tcx.mk_param_from_def(def) + ))); + } + fn check_closure(&self, expr: &hir::Expr, opt_kind: Option, @@ -50,13 +94,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body: &'gcx hir::Expr, expected_sig: Option>) -> Ty<'tcx> { - let expr_def_id = self.tcx.map.local_def_id(expr.id); - let base_def_id = self.tcx.closure_base_def_id(expr_def_id); - debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, expected_sig); + let expr_def_id = self.tcx.map.local_def_id(expr.id); + self.declare_closure(expr_def_id); + let mut fn_ty = AstConv::ty_of_closure(self, hir::Unsafety::Normal, decl, @@ -66,32 +110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let base_generics = self.tcx.item_generics(base_def_id); - // provide junk type parameter defs - the only place that - // cares about anything but the length is instantiation, - // and we don't do that for closures. - let upvar_decls : Vec<_> = self.tcx.with_freevars(expr.id, |fv| { - fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { - index: (base_generics.count() as u32) + (i as u32), - name: token::intern(""), - def_id: expr_def_id, - default_def_id: base_def_id, - default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, - pure_wrt_drop: false, - }).collect() - }); - let num_upvars = upvar_decls.len(); - - self.tcx.generics.memoize(expr_def_id, || self.tcx.alloc_generics(ty::Generics { - parent: Some(base_def_id), - parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), - parent_types: base_generics.parent_types + (base_generics.types.len() as u32), - regions: vec![], - types: upvar_decls, - has_self: false, - })); - + let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); let upvar_tys = self.next_ty_vars(num_upvars); debug!("check_closure: expr.id={:?} upvar_tys={:?}", From 57950982b27c6ab45509c1f2db4a01fa1d2cfebb Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 9 Nov 2016 23:09:28 +0200 Subject: [PATCH 3/4] rustc_trans: translate closures using the collector Translate closures like normal functions, using the trans::collector interface. --- src/librustc_trans/base.rs | 63 +++--- src/librustc_trans/callee.rs | 177 +++++++++++++++- src/librustc_trans/closure.rs | 318 ----------------------------- src/librustc_trans/collector.rs | 28 +-- src/librustc_trans/common.rs | 31 +++ src/librustc_trans/declare.rs | 5 +- src/librustc_trans/lib.rs | 1 - src/librustc_trans/mir/constant.rs | 8 - src/librustc_trans/mir/rvalue.rs | 9 - src/librustc_trans/trans_item.rs | 5 + 10 files changed, 241 insertions(+), 404 deletions(-) delete mode 100644 src/librustc_trans/closure.rs diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a990a7c507fd0..c7cad6455bc30 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1003,34 +1003,41 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { } } -/// Builds an LLVM function out of a source function. -/// -/// If the function closes over its environment a closure will be returned. -pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - llfndecl: ValueRef, - instance: Instance<'tcx>, - sig: &ty::FnSig<'tcx>, - abi: Abi) { +pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { + let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); + // this is an info! to allow collecting monomorphization statistics + // and to allow finding the last function before LLVM aborts from + // release builds. + info!("trans_instance({})", instance); + + let _icx = push_ctxt("trans_instance"); + + let fn_ty = ccx.tcx().item_type(instance.def); + let fn_ty = ccx.tcx().erase_regions(&fn_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); + + let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig); + + let lldecl = match ccx.instances().borrow().get(&instance) { + Some(&val) => val, + None => bug!("Instance `{:?}` not already declared", instance) + }; + ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); - let _icx = push_ctxt("trans_closure"); if !ccx.sess().no_landing_pads() { - attributes::emit_uwtable(llfndecl, true); + attributes::emit_uwtable(lldecl, true); } - // this is an info! to allow collecting monomorphization statistics - // and to allow finding the last function before LLVM aborts from - // release builds. - info!("trans_closure(..., {})", instance); - - let fn_ty = FnType::new(ccx, abi, sig, &[]); + let fn_ty = FnType::new(ccx, abi, &sig, &[]); let (arena, fcx): (TypedArena<_>, FunctionContext); arena = TypedArena::new(); fcx = FunctionContext::new(ccx, - llfndecl, + lldecl, fn_ty, - Some((instance, sig, abi)), + Some((instance, &sig, abi)), &arena); if fcx.mir.is_none() { @@ -1040,26 +1047,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, mir::trans_mir(&fcx); } -pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); - debug!("trans_instance(instance={:?})", instance); - let _icx = push_ctxt("trans_instance"); - - let fn_ty = ccx.tcx().item_type(instance.def); - let fn_ty = ccx.tcx().erase_regions(&fn_ty); - let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); - - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig()); - let abi = fn_ty.fn_abi(); - - let lldecl = match ccx.instances().borrow().get(&instance) { - Some(&val) => val, - None => bug!("Instance `{:?}` not already declared", instance) - }; - - trans_closure(ccx, lldecl, instance, &sig, abi); -} - pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index f49d63b837643..faf65f3f98b09 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -26,11 +26,11 @@ use attributes; use base; use base::*; use build::*; -use closure; use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext}; use consts; use debuginfo::DebugLoc; use declare; +use value::Value; use meth; use monomorphize::{self, Instance}; use trans_item::TransItem; @@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> { // after passing through fulfill_obligation let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let instance = Instance::new(def_id, substs); - let llfn = closure::trans_closure_method(ccx, - vtable_closure.closure_def_id, - vtable_closure.substs, - instance, - trait_closure_kind); + let llfn = trans_closure_method( + ccx, + vtable_closure.closure_def_id, + vtable_closure.substs, + instance, + trait_closure_kind); let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) @@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, monomorphize::apply_param_substs(shared, substs, &ty) } + +fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, + trait_closure_kind: ty::ClosureKind) + -> ValueRef +{ + // If this is a closure, redirect to it. + let (llfn, _) = get_fn(ccx, def_id, substs.substs); + + // If the closure is a Fn closure, but a FnOnce is needed (etc), + // then adapt the self type + let llfn_closure_kind = ccx.tcx().closure_kind(def_id); + + let _icx = push_ctxt("trans_closure_adapter_shim"); + + debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ + trait_closure_kind={:?}, llfn={:?})", + llfn_closure_kind, trait_closure_kind, Value(llfn)); + + match (llfn_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + llfn + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + llfn + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn) + } + _ => { + bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", + llfn_closure_kind, + trait_closure_kind); + } + } +} + +fn trans_fn_once_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, + llreffn: ValueRef) + -> ValueRef +{ + if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { + return llfn; + } + + debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})", + def_id, substs, Value(llreffn)); + + let tcx = ccx.tcx(); + + // Find a version of the closure type. Substitute static for the + // region since it doesn't really matter. + let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs); + let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); + + // Make a version with the type of by-ref closure. + let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs); + sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig.clone() + })); + debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", + llref_fn_ty); + + + // Make a version of the closure type with the same arguments, but + // with argument #0 being by value. + assert_eq!(abi, Abi::RustCall); + sig.0.inputs[0] = closure_ty; + + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + let fn_ty = FnType::new(ccx, abi, &sig, &[]); + + let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: ty::Binder(sig) + })); + + // Create the by-value helper. + let function_name = method_instance.symbol_name(ccx.shared()); + let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); + attributes::set_frame_pointer_elimination(ccx, lloncefn); + + let (block_arena, fcx): (TypedArena<_>, FunctionContext); + block_arena = TypedArena::new(); + fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); + let mut bcx = fcx.init(false); + + + // the first argument (`self`) will be the (by value) closure env. + + let mut llargs = get_params(fcx.llfn); + let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; + let env_arg = &fcx.fn_ty.args[0]; + let llenv = if env_arg.is_indirect() { + llargs[self_idx] + } else { + let scratch = alloc_ty(bcx, closure_ty, "self"); + let mut llarg_idx = self_idx; + env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); + scratch + }; + + debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); + // Adjust llargs such that llargs[self_idx..] has the call arguments. + // For zero-sized closures that means sneaking in a new argument. + if env_arg.is_ignore() { + if self_idx > 0 { + self_idx -= 1; + llargs[self_idx] = llenv; + } else { + llargs.insert(0, llenv); + } + } else { + llargs[self_idx] = llenv; + } + + let dest = fcx.llretslotptr.get(); + + let callee = Callee { + data: Fn(llreffn), + ty: llref_fn_ty + }; + + // Call the by-ref closure body with `self` in a cleanup scope, + // to drop `self` when the body returns, or in case it unwinds. + let self_scope = fcx.push_custom_cleanup_scope(); + fcx.schedule_drop_mem(self_scope, llenv, closure_ty); + + bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; + + fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); + + fcx.finish(bcx, DebugLoc::None); + + ccx.instances().borrow_mut().insert(method_instance, lloncefn); + + lloncefn +} + /// Translates an adapter that implements the `Fn` trait for a fn /// pointer. This is basically the equivalent of something like: /// diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs deleted file mode 100644 index 0cefc49cb425e..0000000000000 --- a/src/librustc_trans/closure.rs +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2012-2014 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 arena::TypedArena; -use llvm::{self, ValueRef, get_params}; -use rustc::hir::def_id::DefId; -use abi::{Abi, FnType}; -use attributes; -use base::*; -use callee::{self, Callee}; -use common::*; -use debuginfo::{DebugLoc}; -use declare; -use monomorphize::{Instance}; -use value::Value; -use rustc::ty::{self, Ty, TyCtxt}; - -use rustc::hir; - -fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_id: DefId, - fn_ty: Ty<'tcx>) - -> Ty<'tcx> { - match tcx.closure_kind(closure_id) { - ty::ClosureKind::Fn => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty) - } - ty::ClosureKind::FnMut => { - tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty) - } - ty::ClosureKind::FnOnce => fn_ty, - } -} - -/// Returns the LLVM function declaration for a closure, creating it if -/// necessary. If the ID does not correspond to a closure ID, returns None. -fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_id: DefId, - substs: ty::ClosureSubsts<'tcx>) - -> ValueRef { - // Normalize type so differences in regions and typedefs don't cause - // duplicate declarations - let tcx = ccx.tcx(); - let substs = tcx.erase_regions(&substs); - let instance = Instance::new(closure_id, substs.substs); - - if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", - instance, Value(llfn)); - return llfn; - } - - let symbol = instance.symbol_name(ccx.shared()); - - // Compute the rust-call form of the closure call method. - let sig = &tcx.closure_type(closure_id, substs).sig; - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs); - let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::RustCall, - sig: ty::Binder(ty::FnSig { - inputs: Some(get_self_type(tcx, closure_id, closure_type)) - .into_iter().chain(sig.inputs).collect(), - output: sig.output, - variadic: false - }) - })); - let llfn = declare::declare_fn(ccx, &symbol, function_type); - - attributes::set_frame_pointer_elimination(ccx, llfn); - - debug!("get_or_create_declaration_if_closure(): inserting new \ - closure {:?}: {:?}", - instance, Value(llfn)); - - // NOTE: We do *not* store llfn in the ccx.instances() map here, - // that is only done, when the closures body is translated. - - llfn -} - -pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>) { - // (*) Note that in the case of inlined functions, the `closure_def_id` will be the - // defid of the closure in its original crate, whereas `id` will be the id of the local - // inlined copy. - debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})", - closure_def_id, closure_substs); - - let tcx = ccx.tcx(); - let _icx = push_ctxt("closure::trans_closure_expr"); - - let instance = Instance::new(closure_def_id, closure_substs.substs); - - // If we have not done so yet, translate this closure's body - if !ccx.instances().borrow().contains_key(&instance) { - let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); - - unsafe { - if ccx.sess().target.target.options.allows_weak_linkage { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage); - llvm::SetUniqueComdat(ccx.llmod(), llfn); - } else { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage); - } - } - - // set an inline hint for all closures - attributes::inline(llfn, attributes::InlineAttr::Hint); - - // Get the type of this closure. Use the current `param_substs` as - // the closure substitutions. This makes sense because the closure - // takes the same set of type arguments as the enclosing fn, and - // this function (`trans_closure`) is invoked at the point - // of the closure expression. - - let sig = &tcx.closure_type(closure_def_id, closure_substs).sig; - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - - let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id, - closure_substs); - let sig = ty::FnSig { - inputs: Some(get_self_type(tcx, closure_def_id, closure_type)) - .into_iter().chain(sig.inputs).collect(), - output: sig.output, - variadic: false - }; - - trans_closure(ccx, - llfn, - instance, - &sig, - Abi::RustCall); - - ccx.instances().borrow_mut().insert(instance, llfn); - } -} - -pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - trait_closure_kind: ty::ClosureKind) - -> ValueRef -{ - // If this is a closure, redirect to it. - let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs); - - // If weak linkage is not allowed, we have to make sure that a local, - // private copy of the closure is available in this codegen unit - if !ccx.sess().target.target.options.allows_weak_linkage && - !ccx.sess().opts.single_codegen_unit() { - - trans_closure_body_via_mir(ccx, closure_def_id, substs); - } - - // If the closure is a Fn closure, but a FnOnce is needed (etc), - // then adapt the self type - let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); - - let _icx = push_ctxt("trans_closure_adapter_shim"); - - debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ - trait_closure_kind={:?}, llfn={:?})", - llfn_closure_kind, trait_closure_kind, Value(llfn)); - - match (llfn_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - llfn - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - llfn - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // 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, method_instance, llfn) - } - _ => { - bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", - llfn_closure_kind, - trait_closure_kind); - } - } -} - -fn trans_fn_once_adapter_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - llreffn: ValueRef) - -> ValueRef -{ - if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { - return llfn; - } - - debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})", - closure_def_id, substs, Value(llreffn)); - - let tcx = ccx.tcx(); - - // Find a version of the closure type. Substitute static for the - // region since it doesn't really matter. - let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs); - let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); - - // Make a version with the type of by-ref closure. - let ty::ClosureTy { unsafety, abi, mut sig } = - tcx.closure_type(closure_def_id, substs); - sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet - let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: sig.clone() - })); - debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", - llref_fn_ty); - - - // Make a version of the closure type with the same arguments, but - // with argument #0 being by value. - assert_eq!(abi, Abi::RustCall); - sig.0.inputs[0] = closure_ty; - - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - let fn_ty = FnType::new(ccx, abi, &sig, &[]); - - let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: ty::Binder(sig) - })); - - // Create the by-value helper. - let function_name = method_instance.symbol_name(ccx.shared()); - let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); - attributes::set_frame_pointer_elimination(ccx, lloncefn); - - let (block_arena, fcx): (TypedArena<_>, FunctionContext); - block_arena = TypedArena::new(); - fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); - let mut bcx = fcx.init(false); - - - // the first argument (`self`) will be the (by value) closure env. - - let mut llargs = get_params(fcx.llfn); - let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; - let env_arg = &fcx.fn_ty.args[0]; - let llenv = if env_arg.is_indirect() { - llargs[self_idx] - } else { - let scratch = alloc_ty(bcx, closure_ty, "self"); - let mut llarg_idx = self_idx; - env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); - scratch - }; - - debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); - // Adjust llargs such that llargs[self_idx..] has the call arguments. - // For zero-sized closures that means sneaking in a new argument. - if env_arg.is_ignore() { - if self_idx > 0 { - self_idx -= 1; - llargs[self_idx] = llenv; - } else { - llargs.insert(0, llenv); - } - } else { - llargs[self_idx] = llenv; - } - - let dest = fcx.llretslotptr.get(); - - let callee = Callee { - data: callee::Fn(llreffn), - ty: llref_fn_ty - }; - - // Call the by-ref closure body with `self` in a cleanup scope, - // to drop `self` when the body returns, or in case it unwinds. - let self_scope = fcx.push_custom_cleanup_scope(); - fcx.schedule_drop_mem(self_scope, llenv, closure_ty); - - bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; - - fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); - - fcx.finish(bcx, DebugLoc::None); - - ccx.instances().borrow_mut().insert(method_instance, lloncefn); - - lloncefn -} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a79719a4d2272..2728a666556e4 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -446,24 +446,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting rvalue {:?}", *rvalue); match *rvalue { - mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id, - ref substs), _) => { - let mir = self.scx.tcx().item_mir(def_id); - - let concrete_substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs.substs); - let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); - - let visitor = MirNeighborCollector { - scx: self.scx, - mir: &mir, - output: self.output, - param_substs: concrete_substs - }; - - visit_mir_and_promoted(visitor, &mir); - } // When doing an cast from a regular pointer to a fat pointer, we // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. @@ -888,10 +870,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, traits::VtableImpl(impl_data) => { Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data)) } - // If we have a closure or a function pointer, we will also encounter - // the concrete closure/function somewhere else (during closure or fn - // pointer construction). That's where we track those things. - traits::VtableClosure(..) | + traits::VtableClosure(closure_data) => { + Some((closure_data.closure_def_id, closure_data.substs.substs)) + } + // Trait object and function pointer shims are always + // instantiated in-place, and as they are just an ABI-adjusting + // indirect call they do not have any dependencies. traits::VtableFnPointer(..) | traits::VtableObject(..) => { None diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 6f3a726215207..a0fac9cc6599e 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -44,6 +44,8 @@ use rustc::hir; use arena::TypedArena; use libc::{c_uint, c_char}; +use std::borrow::Cow; +use std::iter; use std::ops::Deref; use std::ffi::CString; use std::cell::{Cell, RefCell, Ref}; @@ -1069,3 +1071,32 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), } } + +pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) + -> Cow<'tcx, ty::BareFnTy<'tcx>> +{ + match ty.sty { + ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty), + // Shims currently have type TyFnPtr. Not sure this should remain. + ty::TyFnPtr(fty) => Cow::Borrowed(fty), + ty::TyClosure(def_id, substs) => { + let tcx = ccx.tcx(); + let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs); + + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let env_ty = match tcx.closure_kind(def_id) { + ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty), + ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty), + ty::ClosureKind::FnOnce => ty, + }; + + let sig = sig.map_bound(|sig| ty::FnSig { + inputs: iter::once(env_ty).chain(sig.inputs).collect(), + ..sig + }); + Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }) + } + _ => bug!("unexpected type {:?} to ty_fn_sig", ty) + } +} diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 1ec5ca4a563a0..662e3bec66db8 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -25,6 +25,7 @@ use rustc::ty; use abi::{Abi, FnType}; use attributes; use context::CrateContext; +use common; use type_::Type; use value::Value; @@ -103,8 +104,8 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef { pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, fn_type: ty::Ty<'tcx>) -> ValueRef { debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); - let abi = fn_type.fn_abi(); - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig()); + let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let fty = FnType::new(ccx, abi, &sig, &[]); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8ef7f04d4ee14..0757343a8af57 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -109,7 +109,6 @@ mod cabi_x86_64; mod cabi_x86_win64; mod callee; mod cleanup; -mod closure; mod collector; mod common; mod consts; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b8d346b11c13f..bca81fa36458f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -553,14 +553,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } failure?; - // FIXME Shouldn't need to manually trigger closure instantiations. - if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use closure; - closure::trans_closure_body_via_mir(self.ccx, - def_id, - self.monomorphize(&substs)); - } - match *kind { mir::AggregateKind::Array => { self.const_array(dest_ty, &fields) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index f25877b1de12d..bf01db0ffd325 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -133,15 +133,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }, _ => { - // FIXME Shouldn't need to manually trigger closure instantiations. - if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use closure; - - closure::trans_closure_body_via_mir(bcx.ccx(), - def_id, - bcx.monomorphize(&substs)); - } - for (i, operand) in operands.iter().enumerate() { let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 16bc7e212cf54..c5a7dbbcf5480 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -166,6 +166,11 @@ impl<'a, 'tcx> TransItem<'tcx> { llvm::SetUniqueComdat(ccx.llmod(), lldecl); } + if let ty::TyClosure(..) = mono_ty.sty { + // set an inline hint for all closures + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(ccx, &attrs, lldecl); ccx.instances().borrow_mut().insert(instance, lldecl); From d394e75ef6b6b8ea41e62bcbd3023a3e29eb4ee7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 12 Nov 2016 23:20:02 +0200 Subject: [PATCH 4/4] address review comments --- src/librustc/infer/mod.rs | 4 -- src/librustc/ty/subst.rs | 33 ++++++++++---- src/librustc_typeck/check/closure.rs | 66 +++------------------------- src/librustc_typeck/collect.rs | 50 ++++++++++++++++++++- 4 files changed, 80 insertions(+), 73 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 24716c4795134..2d4b36ec18760 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1150,10 +1150,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(true)) } - pub fn next_ty_vars(&self, n: usize) -> Vec> { - (0..n).map(|_i| self.next_ty_var()).collect() - } - pub fn next_int_var_id(&self) -> IntVid { self.int_unification_table .borrow_mut() diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 76d512a20b26e..41fcb09fb2dc7 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -183,6 +183,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { tcx.intern_substs(&substs) } + pub fn extend_to(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + mut mk_region: FR, + mut mk_type: FT) + -> &'tcx Substs<'tcx> + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> + { + let defs = tcx.item_generics(def_id); + let mut result = Vec::with_capacity(defs.count()); + result.extend(self[..].iter().cloned()); + Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); + tcx.intern_substs(&result) + } + fn fill_item(substs: &mut Vec>, tcx: TyCtxt<'a, 'gcx, 'tcx>, defs: &ty::Generics<'tcx>, @@ -195,7 +211,15 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { let parent_defs = tcx.item_generics(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } + Substs::fill_single(substs, defs, mk_region, mk_type) + } + fn fill_single(substs: &mut Vec>, + defs: &ty::Generics<'tcx>, + mk_region: &mut FR, + mk_type: &mut FT) + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { // Handle Self first, before all regions. let mut types = defs.types.iter(); if defs.parent.is_none() && defs.has_self { @@ -275,15 +299,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } - pub fn extend_with_types(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - types: &[Ty<'tcx>]) - -> &'tcx Substs<'tcx> { - tcx.mk_substs( - self[..].iter().cloned().chain( - types.iter().map(|a| Kind::from(*a))) - ) - } - pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>) -> &'tcx Substs<'tcx> { tcx.mk_substs(self.iter().take(generics.count()).cloned()) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 3efbd6b30c220..75287d4064ae1 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,16 +13,11 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; -use rustc::hir::def_id::DefId; use rustc::ty::{self, ToPolyTraitRef, Ty}; -use rustc::ty::subst::Substs; -use rustc::util::common::MemoizationMap; use std::cmp; use syntax::abi::Abi; use rustc::hir; -use syntax::parse::token; - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_closure(&self, expr: &hir::Expr, @@ -45,48 +40,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_closure(expr, expected_kind, decl, body, expected_sig) } - fn declare_closure(&self, def_id: DefId) { - let tcx = self.tcx.global_tcx(); - - tcx.generics.memoize(def_id, || { - let node_id = tcx.map.as_local_node_id(def_id).unwrap(); - let base_def_id = self.tcx.closure_base_def_id(def_id); - let base_generics = tcx.item_generics(base_def_id); - - // provide junk type parameter defs - the only place that - // cares about anything but the length is instantiation, - // and we don't do that for closures. - let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { - fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { - index: (base_generics.count() as u32) + (i as u32), - name: token::intern(""), - def_id: def_id, - default_def_id: base_def_id, - default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, - pure_wrt_drop: false, - }).collect() - }); - - tcx.alloc_generics(ty::Generics { - parent: Some(base_def_id), - parent_regions: base_generics.parent_regions + - (base_generics.regions.len() as u32), - parent_types: base_generics.parent_types + - (base_generics.types.len() as u32), - regions: vec![], - types: upvar_decls, - has_self: false, - }) - }); - - tcx.item_types.memoize(def_id, || tcx.mk_closure(def_id, Substs::for_item( - tcx, def_id, - |def, _| tcx.mk_region(def.to_early_bound_region()), - |def, _| tcx.mk_param_from_def(def) - ))); - } - fn check_closure(&self, expr: &hir::Expr, opt_kind: Option, @@ -99,8 +52,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_sig); let expr_def_id = self.tcx.map.local_def_id(expr.id); - self.declare_closure(expr_def_id); - let mut fn_ty = AstConv::ty_of_closure(self, hir::Unsafety::Normal, decl, @@ -110,18 +61,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 = self.tcx.with_freevars(expr.id, |fv| fv.len()); - let upvar_tys = self.next_ty_vars(num_upvars); - - debug!("check_closure: expr.id={:?} upvar_tys={:?}", - expr.id, - upvar_tys); - - let closure_type = self.tcx.mk_closure( - expr_def_id, - self.parameter_environment.free_substs.extend_with_types(self.tcx, &upvar_tys) + let closure_type = self.tcx.mk_closure(expr_def_id, + self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id, + |_, _| span_bug!(expr.span, "closure has region param"), + |_, _| self.infcx.next_ty_var() + ) ); + debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); + let fn_sig = self.tcx .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 968d5d73e7a8b..816243b3eab47 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -80,7 +80,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::{abi, ast, attr}; -use syntax::parse::token::keywords; +use syntax::parse::token::{self, keywords}; use syntax_pos::Span; use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; @@ -134,6 +134,13 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> intravisit::walk_item(self, item); } + fn visit_expr(&mut self, expr: &hir::Expr) { + if let hir::ExprClosure(..) = expr.node { + convert_closure(self.ccx, expr.id); + } + intravisit::walk_expr(self, expr); + } + fn visit_ty(&mut self, ty: &hir::Ty) { if let hir::TyImplTrait(..) = ty.node { let def_id = self.ccx.tcx.map.local_def_id(ty.id); @@ -559,6 +566,40 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone()); } +fn convert_closure<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + node_id: ast::NodeId) +{ + let tcx = ccx.tcx; + let def_id = tcx.map.local_def_id(node_id); + let base_def_id = tcx.closure_base_def_id(def_id); + let base_generics = generics_of_def_id(ccx, base_def_id); + + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + tcx.generics.borrow_mut().insert(def_id, tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: base_generics.has_self, + })); + + type_of_def_id(ccx, def_id); +} + fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: AssociatedItemContainer, id: ast::NodeId, @@ -1504,6 +1545,13 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } + NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { + ccx.tcx.mk_closure(def_id, Substs::for_item( + ccx.tcx, def_id, + |def, _| ccx.tcx.mk_region(def.to_early_bound_region()), + |def, _| ccx.tcx.mk_param_from_def(def) + )) + } x => { bug!("unexpected sort of node in type_of_def_id(): {:?}", x); }