Skip to content

Translate closures through the collector #37675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 13, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}

1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
@@ -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))]

6 changes: 3 additions & 3 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -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`
13 changes: 8 additions & 5 deletions src/librustc/ty/contents.rs
Original file line number Diff line number Diff line change
@@ -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) => {
7 changes: 2 additions & 5 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -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]>, _>>()?))
}
}

3 changes: 1 addition & 2 deletions src/librustc/ty/flags.rs
Original file line number Diff line number Diff line change
@@ -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) => {
12 changes: 10 additions & 2 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
@@ -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)?;
4 changes: 2 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions src/librustc/ty/outlives.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
9 changes: 2 additions & 7 deletions src/librustc/ty/relate.rs
Original file line number Diff line number Diff line change
@@ -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 })
}
}

12 changes: 4 additions & 8 deletions src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}

23 changes: 16 additions & 7 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty much my only concern, that the upvar types are here - in fact, why are they in the type at all?
Why can't they be like ADTs, with the closure pointing to a list of "fields" which are inferred by typeck?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before trans, closure types need the upvars because they contain lifetimes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But couldn't the types with those lifetimes be stored somewhere else, keyed by DefId?
I believe we already do something like that for the signature of the closure.

///
/// 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()
29 changes: 29 additions & 0 deletions src/librustc/ty/subst.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
@@ -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
3 changes: 1 addition & 2 deletions src/librustc/ty/walk.rs
Original file line number Diff line number Diff line change
@@ -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());
5 changes: 3 additions & 2 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
@@ -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 = ", ";
}
8 changes: 5 additions & 3 deletions src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
Original file line number Diff line number Diff line change
@@ -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) => {
4 changes: 2 additions & 2 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
@@ -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,
Loading