Auto merge of #37675 - arielb1:trans-closure, r=eddyb
Translate closures through the collector Now that old trans is gone, there is no need for the hack of translating closures when they are instantiated. We can translate them like regular items. r? @eddyb
This commit is contained in:
commit
a277f9deb0
39 changed files with 456 additions and 506 deletions
|
@ -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<Ty<'tcx>> {
|
||||
(0..n).map(|_i| self.next_ty_var()).collect()
|
||||
}
|
||||
|
||||
pub fn next_int_var_id(&self) -> IntVid {
|
||||
self.int_unification_table
|
||||
.borrow_mut()
|
||||
|
@ -1657,7 +1653,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))]
|
||||
|
||||
|
|
|
@ -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<T>`, we pass `T`
|
||||
|
|
|
@ -98,10 +98,11 @@ impl TypeContents {
|
|||
TC::OwnsOwned | (*self & TC::OwnsAll)
|
||||
}
|
||||
|
||||
pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
|
||||
F: FnMut(&T) -> TypeContents,
|
||||
pub fn union<I, T, F>(v: I, mut f: F) -> TypeContents where
|
||||
I: IntoIterator<Item=T>,
|
||||
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) => {
|
||||
|
|
|
@ -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<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
|
|||
Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -198,11 +198,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
|
|||
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<Self::Lifted> {
|
||||
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor)
|
||||
self.substs.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Ty<'tcx>>
|
||||
impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
|
||||
#[inline]
|
||||
pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) ->
|
||||
impl Iterator<Item=Ty<'tcx>> + '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()
|
||||
|
|
|
@ -183,6 +183,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
|
|||
tcx.intern_substs(&substs)
|
||||
}
|
||||
|
||||
pub fn extend_to<FR, FT>(&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<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
|
||||
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<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
|
||||
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 {
|
||||
|
@ -274,6 +298,11 @@ 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 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> {
|
||||
|
|
|
@ -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<T:Clone>`).
|
||||
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
|
||||
|
|
|
@ -97,8 +97,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, 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());
|
||||
|
|
|
@ -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 = ", ";
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -1056,10 +1056,10 @@ 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: None,
|
||||
generics: Some(self.encode_generics(def_id)),
|
||||
predicates: None,
|
||||
|
||||
ast: None,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -108,9 +108,9 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
|||
}).collect::<Vec<_>>()
|
||||
},
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_closure(..., {})", instance);
|
||||
info!("trans_instance({})", instance);
|
||||
|
||||
let fn_ty = FnType::new(ccx, abi, sig, &[]);
|
||||
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);
|
||||
|
||||
if !ccx.sess().no_landing_pads() {
|
||||
attributes::emit_uwtable(lldecl, true);
|
||||
}
|
||||
|
||||
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>,
|
||||
|
|
|
@ -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:
|
||||
///
|
||||
|
|
|
@ -1,319 +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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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.func_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 param_substs = closure_substs.func_substs;
|
||||
let instance = Instance::new(closure_def_id, param_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::new(closure_def_id, param_substs),
|
||||
&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
|
||||
}
|
|
@ -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.func_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.
|
||||
|
@ -797,8 +779,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)));
|
||||
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
@ -109,7 +111,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;
|
||||
|
@ -1060,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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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, &[]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,6 @@ mod cabi_x86_64;
|
|||
mod cabi_x86_win64;
|
||||
mod callee;
|
||||
mod cleanup;
|
||||
mod closure;
|
||||
mod collector;
|
||||
mod common;
|
||||
mod consts;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
@ -477,12 +482,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(_) |
|
||||
|
|
|
@ -47,12 +47,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
body: &'gcx hir::Expr,
|
||||
expected_sig: Option<ty::FnSig<'tcx>>)
|
||||
-> Ty<'tcx> {
|
||||
let expr_def_id = self.tcx.map.local_def_id(expr.id);
|
||||
|
||||
debug!("check_closure opt_kind={:?} expected_sig={:?}",
|
||||
opt_kind,
|
||||
expected_sig);
|
||||
|
||||
let expr_def_id = self.tcx.map.local_def_id(expr.id);
|
||||
let mut fn_ty = AstConv::ty_of_closure(self,
|
||||
hir::Unsafety::Normal,
|
||||
decl,
|
||||
|
@ -62,16 +61,14 @@ 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,
|
||||
&upvar_tys);
|
||||
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),
|
||||
|
|
|
@ -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)?
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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("<upvar>"),
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue