Skip to content
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

Translate closures through the collector #37675

Merged
merged 4 commits into from
Nov 13, 2016
Merged
Show file tree
Hide file tree
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
Expand Up @@ -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()
Expand Down Expand Up @@ -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);
}
}

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

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

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

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

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