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))
|
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 {
|
pub fn next_int_var_id(&self) -> IntVid {
|
||||||
self.int_unification_table
|
self.int_unification_table
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -1657,7 +1653,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
{
|
{
|
||||||
if let InferTables::Local(tables) = self.tables {
|
if let InferTables::Local(tables) = self.tables {
|
||||||
if let Some(ty) = tables.borrow().closure_tys.get(&def_id) {
|
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(rustc_private)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
#![cfg_attr(stage0, feature(question_mark))]
|
#![cfg_attr(stage0, feature(question_mark))]
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
|
|
||||||
|
|
|
@ -1912,16 +1912,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
tys.to_vec()
|
tys.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyClosure(_, ref substs) => {
|
ty::TyClosure(def_id, ref substs) => {
|
||||||
// FIXME(#27086). We are invariant w/r/t our
|
// 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
|
// constituent types; this seems RIGHT but also like
|
||||||
// something that a normal type couldn't simulate. Is
|
// something that a normal type couldn't simulate. Is
|
||||||
// this just a gap with the way that PhantomData and
|
// this just a gap with the way that PhantomData and
|
||||||
// OIBIT interact? That is, there is no way to say
|
// OIBIT interact? That is, there is no way to say
|
||||||
// "make me invariant with respect to this TYPE, but
|
// "make me invariant with respect to this TYPE, but
|
||||||
// do not act as though I can reach it"
|
// 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`
|
// for `PhantomData<T>`, we pass `T`
|
||||||
|
|
|
@ -98,10 +98,11 @@ impl TypeContents {
|
||||||
TC::OwnsOwned | (*self & TC::OwnsAll)
|
TC::OwnsOwned | (*self & TC::OwnsAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
|
pub fn union<I, T, F>(v: I, mut f: F) -> TypeContents where
|
||||||
F: FnMut(&T) -> TypeContents,
|
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 {
|
pub fn has_dtor(&self) -> bool {
|
||||||
|
@ -215,8 +216,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||||
}
|
}
|
||||||
ty::TyStr => TC::None,
|
ty::TyStr => TC::None,
|
||||||
|
|
||||||
ty::TyClosure(_, ref substs) => {
|
ty::TyClosure(def_id, ref substs) => {
|
||||||
TypeContents::union(&substs.upvar_tys, |ty| tc_ty(tcx, &ty, cache))
|
TypeContents::union(
|
||||||
|
substs.upvar_tys(def_id, tcx),
|
||||||
|
|ty| tc_ty(tcx, &ty, cache))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyTuple(ref tys) => {
|
ty::TyTuple(ref tys) => {
|
||||||
|
|
|
@ -1446,12 +1446,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
pub fn mk_closure(self,
|
pub fn mk_closure(self,
|
||||||
closure_id: DefId,
|
closure_id: DefId,
|
||||||
substs: &'tcx Substs<'tcx>,
|
substs: &'tcx Substs<'tcx>)
|
||||||
tys: &[Ty<'tcx>])
|
|
||||||
-> Ty<'tcx> {
|
-> Ty<'tcx> {
|
||||||
self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
|
self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
|
||||||
func_substs: substs,
|
substs: substs
|
||||||
upvar_tys: self.intern_type_list(tys)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1574,4 +1572,3 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
|
||||||
Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
|
Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,7 @@ impl FlagComputation {
|
||||||
&ty::TyClosure(_, ref substs) => {
|
&ty::TyClosure(_, ref substs) => {
|
||||||
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
|
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
|
||||||
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
|
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
|
||||||
self.add_substs(&substs.func_substs);
|
self.add_substs(&substs.substs);
|
||||||
self.add_tys(&substs.upvar_tys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&ty::TyInfer(infer) => {
|
&ty::TyInfer(infer) => {
|
||||||
|
|
|
@ -631,7 +631,9 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||||
|
|
||||||
// Perhaps one of the upvars of this closure is non-zero
|
// Perhaps one of the upvars of this closure is non-zero
|
||||||
// Let's recurse and find out!
|
// 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?
|
// Can we use one of the fields in this tuple?
|
||||||
(_, &ty::TyTuple(tys)) => {
|
(_, &ty::TyTuple(tys)) => {
|
||||||
Struct::non_zero_field_path(infcx, tys.iter().cloned())
|
Struct::non_zero_field_path(infcx, tys.iter().cloned())
|
||||||
|
@ -961,7 +963,13 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tuples and closures.
|
// 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) => {
|
ty::TyTuple(tys) => {
|
||||||
let mut st = Struct::new(dl, false);
|
let mut st = Struct::new(dl, false);
|
||||||
st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
|
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
|
// tables by typeck; else, it will be retreived from
|
||||||
// the external crate metadata.
|
// the external crate metadata.
|
||||||
if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) {
|
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);
|
let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
|
||||||
self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone());
|
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.
|
/// 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
|
// in the `subtys` iterator (e.g., when encountering a
|
||||||
// projection).
|
// projection).
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::TyClosure(_, ref substs) => {
|
ty::TyClosure(def_id, ref substs) => {
|
||||||
// FIXME(#27086). We do not accumulate from substs, since they
|
// FIXME(#27086). We do not accumulate from substs, since they
|
||||||
// don't represent reachable data. This means that, in
|
// don't represent reachable data. This means that, in
|
||||||
// practice, some of the lifetime parameters might not
|
// 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,
|
// what func/type parameters are used and unused,
|
||||||
// taking into consideration UFCS and so forth.
|
// 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);
|
self.compute_components(upvar_ty, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -534,13 +534,8 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
|
||||||
-> RelateResult<'tcx, ty::ClosureSubsts<'tcx>>
|
-> RelateResult<'tcx, ty::ClosureSubsts<'tcx>>
|
||||||
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
|
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
|
||||||
{
|
{
|
||||||
let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?;
|
let substs = relate_substs(relation, None, a.substs, b.substs)?;
|
||||||
assert_eq!(a.upvar_tys.len(), b.upvar_tys.len());
|
Ok(ty::ClosureSubsts { substs: substs })
|
||||||
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)))?
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,11 +198,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
|
||||||
impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
|
impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
|
||||||
type Lifted = ty::ClosureSubsts<'tcx>;
|
type Lifted = ty::ClosureSubsts<'tcx>;
|
||||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
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)| {
|
tcx.lift(&self.substs).map(|substs| {
|
||||||
ty::ClosureSubsts {
|
ty::ClosureSubsts { substs: substs }
|
||||||
func_substs: substs,
|
|
||||||
upvar_tys: upvar_tys
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,13 +651,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
|
||||||
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
|
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
|
||||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||||
ty::ClosureSubsts {
|
ty::ClosureSubsts {
|
||||||
func_substs: self.func_substs.fold_with(folder),
|
substs: self.substs.fold_with(folder),
|
||||||
upvar_tys: self.upvar_tys.fold_with(folder),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
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
|
//! This module contains TypeVariants and its major components
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||||
|
@ -254,15 +255,23 @@ pub enum TypeVariants<'tcx> {
|
||||||
/// handle). Plus it fixes an ICE. :P
|
/// handle). Plus it fixes an ICE. :P
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct ClosureSubsts<'tcx> {
|
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
|
/// These are separated out because trans wants to pass them around
|
||||||
/// when monomorphizing.
|
/// when monomorphizing.
|
||||||
pub func_substs: &'tcx Substs<'tcx>,
|
pub substs: &'tcx Substs<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The types of the upvars. The list parallels the freevars and
|
impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
|
||||||
/// `upvar_borrows` lists. These are kept distinct so that we can
|
#[inline]
|
||||||
/// easily index into them.
|
pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) ->
|
||||||
pub upvar_tys: &'tcx Slice<Ty<'tcx>>
|
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)]
|
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||||
|
@ -1234,7 +1243,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
substs.regions().collect()
|
substs.regions().collect()
|
||||||
}
|
}
|
||||||
TyClosure(_, ref substs) => {
|
TyClosure(_, ref substs) => {
|
||||||
substs.func_substs.regions().collect()
|
substs.substs.regions().collect()
|
||||||
}
|
}
|
||||||
TyProjection(ref data) => {
|
TyProjection(ref data) => {
|
||||||
data.trait_ref.substs.regions().collect()
|
data.trait_ref.substs.regions().collect()
|
||||||
|
|
|
@ -183,6 +183,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
|
||||||
tcx.intern_substs(&substs)
|
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>>,
|
fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
defs: &ty::Generics<'tcx>,
|
defs: &ty::Generics<'tcx>,
|
||||||
|
@ -195,7 +211,15 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
|
||||||
let parent_defs = tcx.item_generics(def_id);
|
let parent_defs = tcx.item_generics(def_id);
|
||||||
Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
|
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.
|
// Handle Self first, before all regions.
|
||||||
let mut types = defs.types.iter();
|
let mut types = defs.types.iter();
|
||||||
if defs.parent.is_none() && defs.has_self {
|
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);
|
let defs = tcx.item_generics(source_ancestor);
|
||||||
tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
|
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> {
|
impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//! misc. type-system utilities too small to deserve their own file
|
//! misc. type-system utilities too small to deserve their own file
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
use hir::map::DefPathData;
|
||||||
use infer::InferCtxt;
|
use infer::InferCtxt;
|
||||||
use hir::map as ast_map;
|
use hir::map as ast_map;
|
||||||
use hir::pat_util;
|
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>`).
|
// (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
|
||||||
return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params");
|
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
|
/// 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());
|
stack.extend(substs.types().rev());
|
||||||
}
|
}
|
||||||
ty::TyClosure(_, ref substs) => {
|
ty::TyClosure(_, ref substs) => {
|
||||||
stack.extend(substs.func_substs.types().rev());
|
stack.extend(substs.substs.types().rev());
|
||||||
stack.extend(substs.upvar_tys.iter().cloned().rev());
|
|
||||||
}
|
}
|
||||||
ty::TyTuple(ts) => {
|
ty::TyTuple(ts) => {
|
||||||
stack.extend(ts.iter().cloned().rev());
|
stack.extend(ts.iter().cloned().rev());
|
||||||
|
|
|
@ -907,13 +907,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||||
}
|
}
|
||||||
TyStr => write!(f, "str"),
|
TyStr => write!(f, "str"),
|
||||||
TyClosure(did, substs) => ty::tls::with(|tcx| {
|
TyClosure(did, substs) => ty::tls::with(|tcx| {
|
||||||
|
let upvar_tys = substs.upvar_tys(did, tcx);
|
||||||
write!(f, "[closure")?;
|
write!(f, "[closure")?;
|
||||||
|
|
||||||
if let Some(node_id) = tcx.map.as_local_node_id(did) {
|
if let Some(node_id) = tcx.map.as_local_node_id(did) {
|
||||||
write!(f, "@{:?}", tcx.map.span(node_id))?;
|
write!(f, "@{:?}", tcx.map.span(node_id))?;
|
||||||
let mut sep = " ";
|
let mut sep = " ";
|
||||||
tcx.with_freevars(node_id, |freevars| {
|
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 def_id = freevar.def.def_id();
|
||||||
let node_id = tcx.map.as_local_node_id(def_id).unwrap();
|
let node_id = tcx.map.as_local_node_id(def_id).unwrap();
|
||||||
write!(f,
|
write!(f,
|
||||||
|
@ -930,7 +931,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||||
// visible in trans bug reports, I imagine.
|
// visible in trans bug reports, I imagine.
|
||||||
write!(f, "@{:?}", did)?;
|
write!(f, "@{:?}", did)?;
|
||||||
let mut sep = " ";
|
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)?;
|
write!(f, "{}{}:{}", sep, index, upvar_ty)?;
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
|
|
|
@ -709,9 +709,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
ty::TyAdt(def, substs) => {
|
ty::TyAdt(def, substs) => {
|
||||||
self.open_drop_for_adt(c, def, substs)
|
self.open_drop_for_adt(c, def, substs)
|
||||||
}
|
}
|
||||||
ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
|
ty::TyClosure(def_id, substs) => {
|
||||||
upvar_tys: tys, ..
|
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)
|
self.open_drop_for_tuple(c, tys)
|
||||||
}
|
}
|
||||||
ty::TyBox(ty) => {
|
ty::TyBox(ty) => {
|
||||||
|
|
|
@ -1056,10 +1056,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
stability: None,
|
stability: None,
|
||||||
deprecation: None,
|
deprecation: None,
|
||||||
|
|
||||||
ty: None,
|
ty: Some(self.encode_item_type(def_id)),
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: LazySeq::empty(),
|
variances: LazySeq::empty(),
|
||||||
generics: None,
|
generics: Some(self.encode_generics(def_id)),
|
||||||
predicates: None,
|
predicates: None,
|
||||||
|
|
||||||
ast: 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| {
|
let upvars = cx.tcx.with_freevars(expr.id, |freevars| {
|
||||||
freevars.iter()
|
freevars.iter()
|
||||||
.enumerate()
|
.zip(substs.upvar_tys(def_id, cx.tcx))
|
||||||
.map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i]))
|
.map(|(fv, ty)| capture_freevar(cx, expr, fv, ty))
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
ExprKind::Closure {
|
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() => {
|
ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => {
|
||||||
(&adt_def.variants[0], substs)
|
(&adt_def.variants[0], substs)
|
||||||
}
|
}
|
||||||
ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
|
ty::TyClosure(def_id, substs) => {
|
||||||
upvar_tys: tys, ..
|
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()) {
|
return match tys.get(field.index()) {
|
||||||
Some(&ty) => Ok(ty),
|
Some(&ty) => Ok(ty),
|
||||||
None => Err(FieldAccessError::OutOfRange {
|
None => Err(FieldAccessError::OutOfRange {
|
||||||
|
|
|
@ -108,9 +108,9 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
||||||
}).collect::<Vec<_>>()
|
}).collect::<Vec<_>>()
|
||||||
},
|
},
|
||||||
ty::TyTuple(fields) => fields.to_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);}
|
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)
|
_ => 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.
|
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));
|
||||||
/// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is an info! to allow collecting monomorphization statistics
|
// this is an info! to allow collecting monomorphization statistics
|
||||||
// and to allow finding the last function before LLVM aborts from
|
// and to allow finding the last function before LLVM aborts from
|
||||||
// release builds.
|
// 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);
|
let (arena, fcx): (TypedArena<_>, FunctionContext);
|
||||||
arena = TypedArena::new();
|
arena = TypedArena::new();
|
||||||
fcx = FunctionContext::new(ccx,
|
fcx = FunctionContext::new(ccx,
|
||||||
llfndecl,
|
lldecl,
|
||||||
fn_ty,
|
fn_ty,
|
||||||
Some((instance, sig, abi)),
|
Some((instance, &sig, abi)),
|
||||||
&arena);
|
&arena);
|
||||||
|
|
||||||
if fcx.mir.is_none() {
|
if fcx.mir.is_none() {
|
||||||
|
@ -1040,26 +1047,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
mir::trans_mir(&fcx);
|
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>,
|
pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
substs: &'tcx Substs<'tcx>,
|
substs: &'tcx Substs<'tcx>,
|
||||||
|
|
|
@ -26,11 +26,11 @@ use attributes;
|
||||||
use base;
|
use base;
|
||||||
use base::*;
|
use base::*;
|
||||||
use build::*;
|
use build::*;
|
||||||
use closure;
|
|
||||||
use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
|
use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
|
||||||
use consts;
|
use consts;
|
||||||
use debuginfo::DebugLoc;
|
use debuginfo::DebugLoc;
|
||||||
use declare;
|
use declare;
|
||||||
|
use value::Value;
|
||||||
use meth;
|
use meth;
|
||||||
use monomorphize::{self, Instance};
|
use monomorphize::{self, Instance};
|
||||||
use trans_item::TransItem;
|
use trans_item::TransItem;
|
||||||
|
@ -147,7 +147,8 @@ impl<'tcx> Callee<'tcx> {
|
||||||
// after passing through fulfill_obligation
|
// after passing through fulfill_obligation
|
||||||
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
||||||
let instance = Instance::new(def_id, substs);
|
let instance = Instance::new(def_id, substs);
|
||||||
let llfn = closure::trans_closure_method(ccx,
|
let llfn = trans_closure_method(
|
||||||
|
ccx,
|
||||||
vtable_closure.closure_def_id,
|
vtable_closure.closure_def_id,
|
||||||
vtable_closure.substs,
|
vtable_closure.substs,
|
||||||
instance,
|
instance,
|
||||||
|
@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
|
||||||
monomorphize::apply_param_substs(shared, substs, &ty)
|
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
|
/// Translates an adapter that implements the `Fn` trait for a fn
|
||||||
/// pointer. This is basically the equivalent of something like:
|
/// 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);
|
debug!("visiting rvalue {:?}", *rvalue);
|
||||||
|
|
||||||
match *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
|
// 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
|
// have to instantiate all methods of the trait being cast to, so we
|
||||||
// can build the appropriate vtable.
|
// can build the appropriate vtable.
|
||||||
|
@ -797,8 +779,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::TyClosure(_, substs) => {
|
ty::TyClosure(def_id, substs) => {
|
||||||
for upvar_ty in substs.upvar_tys {
|
for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) {
|
||||||
let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty);
|
let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty);
|
||||||
if glue::type_needs_drop(scx.tcx(), upvar_ty) {
|
if glue::type_needs_drop(scx.tcx(), upvar_ty) {
|
||||||
output.push(TransItem::DropGlue(DropGlueKind::Ty(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) => {
|
traits::VtableImpl(impl_data) => {
|
||||||
Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &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
|
traits::VtableClosure(closure_data) => {
|
||||||
// the concrete closure/function somewhere else (during closure or fn
|
Some((closure_data.closure_def_id, closure_data.substs.substs))
|
||||||
// pointer construction). That's where we track those things.
|
}
|
||||||
traits::VtableClosure(..) |
|
// 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::VtableFnPointer(..) |
|
||||||
traits::VtableObject(..) => {
|
traits::VtableObject(..) => {
|
||||||
None
|
None
|
||||||
|
|
|
@ -44,6 +44,8 @@ use rustc::hir;
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use libc::{c_uint, c_char};
|
use libc::{c_uint, c_char};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::iter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::cell::{Cell, RefCell, Ref};
|
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]),
|
Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]),
|
||||||
monomorphize::field_ty(ccx.tcx(), substs, &fields[1])])
|
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) => {
|
ty::TyTuple(tys) => {
|
||||||
if tys.len() != 2 {
|
if tys.len() != 2 {
|
||||||
return None;
|
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),
|
_ => 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)
|
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,
|
prepare_tuple_metadata(cx,
|
||||||
t,
|
t,
|
||||||
&substs.upvar_tys,
|
&upvar_tys,
|
||||||
unique_type_id,
|
unique_type_id,
|
||||||
usage_site_span).finalize(cx)
|
usage_site_span).finalize(cx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ use llvm::{ModuleRef, ContextRef, ValueRef};
|
||||||
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
|
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
|
||||||
FlagPrototyped};
|
FlagPrototyped};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::map::DefPathData;
|
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
|
|
||||||
use abi::Abi;
|
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.
|
// Find the enclosing function, in case this is a closure.
|
||||||
let mut fn_def_id = instance.def;
|
let def_key = cx.tcx().def_key(instance.def);
|
||||||
let mut def_key = cx.tcx().def_key(fn_def_id);
|
|
||||||
let mut name = def_key.disambiguated_data.data.to_string();
|
let mut name = def_key.disambiguated_data.data.to_string();
|
||||||
let name_len = name.len();
|
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?");
|
let fn_def_id = cx.tcx().closure_base_def_id(instance.def);
|
||||||
def_key = cx.tcx().def_key(fn_def_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get_template_parameters() will append a `<...>` clause to the function
|
// Get_template_parameters() will append a `<...>` clause to the function
|
||||||
// name if necessary.
|
// name if necessary.
|
||||||
let generics = cx.tcx().item_generics(fn_def_id);
|
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,
|
let template_parameters = get_template_parameters(cx,
|
||||||
&generics,
|
&generics,
|
||||||
instance.substs,
|
substs,
|
||||||
file_metadata,
|
file_metadata,
|
||||||
&mut name);
|
&mut name);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use rustc::ty;
|
||||||
use abi::{Abi, FnType};
|
use abi::{Abi, FnType};
|
||||||
use attributes;
|
use attributes;
|
||||||
use context::CrateContext;
|
use context::CrateContext;
|
||||||
|
use common;
|
||||||
use type_::Type;
|
use type_::Type;
|
||||||
use value::Value;
|
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,
|
pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
|
||||||
fn_type: ty::Ty<'tcx>) -> ValueRef {
|
fn_type: ty::Ty<'tcx>) -> ValueRef {
|
||||||
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
|
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
|
||||||
let abi = fn_type.fn_abi();
|
let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type);
|
||||||
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig());
|
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
|
||||||
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
|
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
|
||||||
|
|
||||||
let fty = FnType::new(ccx, abi, &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;
|
let mut cx = cx;
|
||||||
match t.sty {
|
match t.sty {
|
||||||
ty::TyClosure(_, ref substs) => {
|
ty::TyClosure(def_id, substs) => {
|
||||||
for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() {
|
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);
|
let llupvar = adt::trans_field_ptr(cx, t, value, Disr(0), i);
|
||||||
cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None);
|
cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None);
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,6 @@ mod cabi_x86_64;
|
||||||
mod cabi_x86_win64;
|
mod cabi_x86_win64;
|
||||||
mod callee;
|
mod callee;
|
||||||
mod cleanup;
|
mod cleanup;
|
||||||
mod closure;
|
|
||||||
mod collector;
|
mod collector;
|
||||||
mod common;
|
mod common;
|
||||||
mod consts;
|
mod consts;
|
||||||
|
|
|
@ -553,14 +553,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
failure?;
|
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 {
|
match *kind {
|
||||||
mir::AggregateKind::Array => {
|
mir::AggregateKind::Array => {
|
||||||
self.const_array(dest_ty, &fields)
|
self.const_array(dest_ty, &fields)
|
||||||
|
|
|
@ -470,8 +470,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
} else {
|
} else {
|
||||||
(arg_ty, false)
|
(arg_ty, false)
|
||||||
};
|
};
|
||||||
let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty {
|
let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty {
|
||||||
&substs.upvar_tys[..]
|
substs.upvar_tys(def_id, tcx)
|
||||||
} else {
|
} else {
|
||||||
bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty);
|
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() {
|
for (i, operand) in operands.iter().enumerate() {
|
||||||
let op = self.trans_operand(&bcx, operand);
|
let op = self.trans_operand(&bcx, operand);
|
||||||
// Do not generate stores and GEPis for zero-sized fields.
|
// Do not generate stores and GEPis for zero-sized fields.
|
||||||
|
|
|
@ -166,6 +166,11 @@ impl<'a, 'tcx> TransItem<'tcx> {
|
||||||
llvm::SetUniqueComdat(ccx.llmod(), lldecl);
|
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);
|
attributes::from_fn_attrs(ccx, &attrs, lldecl);
|
||||||
|
|
||||||
ccx.instances().borrow_mut().insert(instance, 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);
|
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);
|
push_item_name(tcx, def_id, output);
|
||||||
output.push_str("{");
|
output.push_str("{");
|
||||||
output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
|
output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
|
||||||
output.push_str("}");
|
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::TyError |
|
||||||
ty::TyInfer(_) |
|
ty::TyInfer(_) |
|
||||||
|
|
|
@ -47,12 +47,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
body: &'gcx hir::Expr,
|
body: &'gcx hir::Expr,
|
||||||
expected_sig: Option<ty::FnSig<'tcx>>)
|
expected_sig: Option<ty::FnSig<'tcx>>)
|
||||||
-> Ty<'tcx> {
|
-> Ty<'tcx> {
|
||||||
let expr_def_id = self.tcx.map.local_def_id(expr.id);
|
|
||||||
|
|
||||||
debug!("check_closure opt_kind={:?} expected_sig={:?}",
|
debug!("check_closure opt_kind={:?} expected_sig={:?}",
|
||||||
opt_kind,
|
opt_kind,
|
||||||
expected_sig);
|
expected_sig);
|
||||||
|
|
||||||
|
let expr_def_id = self.tcx.map.local_def_id(expr.id);
|
||||||
let mut fn_ty = AstConv::ty_of_closure(self,
|
let mut fn_ty = AstConv::ty_of_closure(self,
|
||||||
hir::Unsafety::Normal,
|
hir::Unsafety::Normal,
|
||||||
decl,
|
decl,
|
||||||
|
@ -62,16 +61,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// Create type variables (for now) to represent the transformed
|
// Create type variables (for now) to represent the transformed
|
||||||
// types of upvars. These will be unified during the upvar
|
// types of upvars. These will be unified during the upvar
|
||||||
// inference phase (`upvar.rs`).
|
// 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,
|
let closure_type = self.tcx.mk_closure(expr_def_id,
|
||||||
self.parameter_environment.free_substs,
|
self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id,
|
||||||
&upvar_tys);
|
|_, _| 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
|
let fn_sig = self.tcx
|
||||||
.liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyTuple(tys) |
|
ty::TyClosure(def_id, substs) => {
|
||||||
ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) => {
|
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 {
|
for ty in tys {
|
||||||
iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
|
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).
|
// inference algorithm will reject it).
|
||||||
|
|
||||||
// Extract the type variables UV0...UVn.
|
// Extract the type variables UV0...UVn.
|
||||||
let closure_substs = match self.fcx.node_ty(id).sty {
|
let (def_id, closure_substs) = match self.fcx.node_ty(id).sty {
|
||||||
ty::TyClosure(_, ref substs) => substs,
|
ty::TyClosure(def_id, substs) => (def_id, substs),
|
||||||
ref t => {
|
ref t => {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
span,
|
span,
|
||||||
|
@ -197,7 +197,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
let final_upvar_tys = self.final_upvar_tys(id);
|
let final_upvar_tys = self.final_upvar_tys(id);
|
||||||
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
|
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
|
||||||
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);
|
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 std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
|
|
||||||
use syntax::{abi, ast, attr};
|
use syntax::{abi, ast, attr};
|
||||||
use syntax::parse::token::keywords;
|
use syntax::parse::token::{self, keywords};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
use rustc::hir::{self, intravisit, map as hir_map, print as pprust};
|
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);
|
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) {
|
fn visit_ty(&mut self, ty: &hir::Ty) {
|
||||||
if let hir::TyImplTrait(..) = ty.node {
|
if let hir::TyImplTrait(..) = ty.node {
|
||||||
let def_id = self.ccx.tcx.map.local_def_id(ty.id);
|
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());
|
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>,
|
fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
container: AssociatedItemContainer,
|
container: AssociatedItemContainer,
|
||||||
id: ast::NodeId,
|
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 => {
|
x => {
|
||||||
bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
|
bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue