introduce closure_env_ty
helper to compute ty of closure env arg
Previously the code was somewhat duplicated.
This commit is contained in:
parent
7f247add41
commit
fa813f74a2
@ -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
|
||||
|
@ -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<ty::Binder<Ty<'tcx>>>
|
||||
{
|
||||
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> {
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user