diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 07573a48c03..afe999cede7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1921,6 +1921,12 @@ impl<'a, 'gcx, 'tcx> FieldDef { } } +/// Represents the various closure traits in the Rust language. This +/// will determine the type of the environment (`self`, in the +/// desuaring) argument that the closure expects. +/// +/// You can get the environment type of a closure using +/// `tcx.closure_env_ty()`. #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum ClosureKind { // Warning: Ordering is significant here! The ordering is chosen diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 23dd3f1bc2b..e19bab46402 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -634,6 +634,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id } + /// Given the def-id and substs a closure, creates the type of + /// `self` argument that the closure expects. For example, for a + /// `Fn` closure, this would return a reference type `&T` where + /// `T=closure_ty`. + /// + /// Returns `None` if this closure's kind has not yet been inferred. + /// This should only be possible during type checking. + /// + /// Note that the return value is a late-bound region and hence + /// wrapped in a binder. + pub fn closure_env_ty(self, + closure_def_id: DefId, + closure_substs: ty::ClosureSubsts<'tcx>) + -> Option>> + { + let closure_ty = self.mk_closure(closure_def_id, closure_substs); + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self); + let closure_kind = closure_kind_ty.to_opt_closure_kind()?; + let env_ty = match closure_kind { + ty::ClosureKind::Fn => self.mk_imm_ref(self.mk_region(env_region), closure_ty), + ty::ClosureKind::FnMut => self.mk_mut_ref(self.mk_region(env_region), closure_ty), + ty::ClosureKind::FnOnce => closure_ty, + }; + Some(ty::Binder(env_ty)) + } + /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 4349820dbe9..d814b092c9d 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -100,7 +100,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // HACK(eddyb) Avoid having RustCall on closures, // as it adds unnecessary (and wrong) auto-tupling. abi = Abi::Rust; - Some((closure_self_ty(tcx, id, body_id), None)) + Some((liberated_closure_env_ty(tcx, id, body_id), None)) } ty::TyGenerator(..) => { let gen_ty = tcx.body_tables(body_id).node_id_to_type(fn_hir_id); @@ -246,10 +246,10 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from -pub fn closure_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - closure_expr_id: ast::NodeId, - body_id: hir::BodyId) - -> Ty<'tcx> { +fn liberated_closure_env_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + closure_expr_id: ast::NodeId, + body_id: hir::BodyId) + -> Ty<'tcx> { let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id); let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id); @@ -258,24 +258,8 @@ pub fn closure_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, _ => bug!("closure expr does not have closure type: {:?}", closure_ty) }; - let region = ty::ReFree(ty::FreeRegion { - scope: closure_def_id, - bound_region: ty::BoundRegion::BrEnv, - }); - let region = tcx.mk_region(region); - - match closure_substs.closure_kind_ty(closure_def_id, tcx).to_opt_closure_kind().unwrap() { - ty::ClosureKind::Fn => - tcx.mk_ref(region, - ty::TypeAndMut { ty: closure_ty, - mutbl: hir::MutImmutable }), - ty::ClosureKind::FnMut => - tcx.mk_ref(region, - ty::TypeAndMut { ty: closure_ty, - mutbl: hir::MutMutable }), - ty::ClosureKind::FnOnce => - closure_ty - } + let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap(); + tcx.liberate_late_bound_regions(closure_def_id, &closure_env_ty) } struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 1f92c106784..405647af324 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -395,15 +395,9 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tcx = ccx.tcx(); let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs); - let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); - let env_ty = match substs.closure_kind(def_id, tcx) { - 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 env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); sig.map_bound(|sig| tcx.mk_fn_sig( - iter::once(env_ty).chain(sig.inputs().iter().cloned()), + iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), sig.output(), sig.variadic, sig.unsafety,