Skip to content

Change Substs to type alias for Slice<Kind> for interning #37100

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 3 commits into from
Oct 15, 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
4 changes: 2 additions & 2 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::region::CodeExtent;
use mir::tcx::LvalueTy;
use ty::subst::{Subst, Substs};
use ty::subst::{Kind, Subst, Substs};
use ty::adjustment;
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
Expand Down Expand Up @@ -1208,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn type_var_for_def(&self,
span: Span,
def: &ty::TypeParameterDef<'tcx>,
substs: &Substs<'tcx>)
substs: &[Kind<'tcx>])
-> Ty<'tcx> {
let default = def.default.map(|default| {
type_variable::Default {
Expand Down
21 changes: 12 additions & 9 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use middle::free_region::FreeRegionMap;
use middle::region::RegionMaps;
use middle::resolve_lifetime;
use middle::stability;
use ty::subst::Substs;
use ty::subst::{Kind, Substs};
use traits;
use ty::{self, TraitRef, Ty, TypeAndMut};
use ty::{TyS, TypeVariants, Slice};
Expand Down Expand Up @@ -55,7 +55,7 @@ pub struct CtxtArenas<'tcx> {
// internings
type_: TypedArena<TyS<'tcx>>,
type_list: TypedArena<Vec<Ty<'tcx>>>,
substs: TypedArena<Substs<'tcx>>,
substs: TypedArena<Vec<Kind<'tcx>>>,
bare_fn: TypedArena<BareFnTy<'tcx>>,
region: TypedArena<Region>,
stability: TypedArena<attr::Stability>,
Expand Down Expand Up @@ -824,7 +824,7 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
type Lifted = &'tcx Substs<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(*self) {
if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(&self[..]) {
if *self as *const _ == substs as *const _ {
return Some(substs);
}
Expand Down Expand Up @@ -1097,9 +1097,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, Slice<Ty<'tcx>>> {
}
}

impl<'tcx: 'lcx, 'lcx> Borrow<Substs<'lcx>> for Interned<'tcx, Substs<'tcx>> {
fn borrow<'a>(&'a self) -> &'a Substs<'lcx> {
self.0
impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
fn borrow<'a>(&'a self) -> &'a [Kind<'lcx>] {
&self.0[..]
}
}

Expand Down Expand Up @@ -1189,9 +1189,6 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
}

direct_interners!('tcx,
substs: mk_substs(|substs: &Substs| {
substs.params().iter().any(keep_local)
}) -> Substs<'tcx>,
bare_fn: mk_bare_fn(|fty: &BareFnTy| {
keep_local(&fty.sig)
}) -> BareFnTy<'tcx>,
Expand All @@ -1209,6 +1206,12 @@ intern_method!('tcx,
}, keep_local) -> Slice<Ty<'tcx>>
);

intern_method!('tcx,
substs: mk_substs(Vec<Kind<'tcx>>, Deref::deref, |xs: &[Kind]| -> &Slice<Kind> {
unsafe { mem::transmute(xs) }
}, keep_local) -> Slice<Kind<'tcx>>
);

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Create an unsafe fn ty based on a safe fn ty.
pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>;
impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {}

/// A wrapper for slices with the additioanl invariant
/// A wrapper for slices with the additional invariant
/// that the slice is interned and no other slice with
/// the same contents can exist in the same context.
/// This means we can use pointer + length for both
Expand Down
106 changes: 47 additions & 59 deletions src/librustc/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// Type substitutions.

use hir::def_id::DefId;
use ty::{self, Ty, TyCtxt};
use ty::{self, Slice, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};

use serialize::{self, Encodable, Encoder, Decodable, Decoder};
Expand Down Expand Up @@ -161,26 +161,19 @@ impl<'tcx> Decodable for Kind<'tcx> {
}

/// A substitution mapping type/region parameters to new values.
#[derive(Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)]
pub struct Substs<'tcx> {
params: Vec<Kind<'tcx>>
}
pub type Substs<'tcx> = Slice<Kind<'tcx>>;

impl<'a, 'gcx, 'tcx> Substs<'tcx> {
pub fn new<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
-> &'tcx Substs<'tcx>
where I: IntoIterator<Item=Kind<'tcx>> {
tcx.mk_substs(Substs {
params: params.into_iter().collect()
})
tcx.mk_substs(params.into_iter().collect())
}

pub fn maybe_new<I, E>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
-> Result<&'tcx Substs<'tcx>, E>
where I: IntoIterator<Item=Result<Kind<'tcx>, E>> {
Ok(tcx.mk_substs(Substs {
params: params.into_iter().collect::<Result<_, _>>()?
}))
Ok(Substs::new(tcx, params.into_iter().collect::<Result<Vec<_>, _>>()?))
}

pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>,
Expand All @@ -193,7 +186,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
}

pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
Substs::new(tcx, vec![])
Substs::new(tcx, iter::empty())
}

/// Creates a Substs for generic parameter definitions,
Expand All @@ -206,82 +199,82 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
mut mk_region: FR,
mut mk_type: FT)
-> &'tcx Substs<'tcx>
where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
let defs = tcx.lookup_generics(def_id);
let mut substs = Substs {
params: Vec::with_capacity(defs.count())
};
let mut substs = Vec::with_capacity(defs.count());

substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type);
Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);

tcx.mk_substs(substs)
Substs::new(tcx, substs)
}

fn fill_item<FR, FT>(&mut self,
fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
defs: &ty::Generics<'tcx>,
mk_region: &mut FR,
mk_type: &mut FT)
where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {

if let Some(def_id) = defs.parent {
let parent_defs = tcx.lookup_generics(def_id);
self.fill_item(tcx, parent_defs, mk_region, mk_type);
Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
}

// Handle Self first, before all regions.
let mut types = defs.types.iter();
if defs.parent.is_none() && defs.has_self {
let def = types.next().unwrap();
let ty = mk_type(def, self);
assert_eq!(def.index as usize, self.params.len());
self.params.push(Kind::from(ty));
let ty = mk_type(def, substs);
assert_eq!(def.index as usize, substs.len());
substs.push(Kind::from(ty));
}

for def in &defs.regions {
let region = mk_region(def, self);
assert_eq!(def.index as usize, self.params.len());
self.params.push(Kind::from(region));
let region = mk_region(def, substs);
assert_eq!(def.index as usize, substs.len());
substs.push(Kind::from(region));
}

for def in types {
let ty = mk_type(def, self);
assert_eq!(def.index as usize, self.params.len());
self.params.push(Kind::from(ty));
let ty = mk_type(def, substs);
assert_eq!(def.index as usize, substs.len());
substs.push(Kind::from(ty));
}
}

pub fn is_noop(&self) -> bool {
self.params.is_empty()
self.is_empty()
}

#[inline]
pub fn params(&self) -> &[Kind<'tcx>] {
&self.params
// FIXME (dikaiosune) this should be removed, and corresponding compilation errors fixed
self
}

#[inline]
pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
self.params.iter().filter_map(|k| k.as_type())
self.iter().filter_map(|k| k.as_type())
}

#[inline]
pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=&'tcx ty::Region> + 'a {
self.params.iter().filter_map(|k| k.as_region())
self.iter().filter_map(|k| k.as_region())
}

#[inline]
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
self.params[i].as_type().unwrap_or_else(|| {
bug!("expected type for param #{} in {:?}", i, self.params);
self[i].as_type().unwrap_or_else(|| {
bug!("expected type for param #{} in {:?}", i, self);
})
}

#[inline]
pub fn region_at(&self, i: usize) -> &'tcx ty::Region {
self.params[i].as_region().unwrap_or_else(|| {
bug!("expected region for param #{} in {:?}", i, self.params);
self[i].as_region().unwrap_or_else(|| {
bug!("expected region for param #{} in {:?}", i, self);
})
}

Expand All @@ -305,27 +298,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
target_substs: &Substs<'tcx>)
-> &'tcx Substs<'tcx> {
let defs = tcx.lookup_generics(source_ancestor);
tcx.mk_substs(Substs {
params: target_substs.params.iter()
.chain(&self.params[defs.own_count()..]).cloned().collect()
})
Substs::new(tcx, target_substs.iter().chain(&self[defs.own_count()..]).cloned())
}
}

impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let params = self.params.iter().map(|k| k.fold_with(folder)).collect();
folder.tcx().mk_substs(Substs {
params: params
})
let params = self.iter().map(|k| k.fold_with(folder)).collect();
Copy link
Member

Choose a reason for hiding this comment

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

Unnecessary .collect().

Copy link
Member Author

@anp anp Oct 12, 2016

Choose a reason for hiding this comment

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

Perhaps you can help me think of a better solution -- Substs::new takes IntoIterator<Item=Kind>, which is what we'd really want here. But the closure in the map call here borrows folder mutably, and Substs::new wants a TyCtxt from the folder, trying to borrow that immutably. And trying to create a simultaneous pair of mutable/immutable borrows obviously creates a borrow error.

The workaround I decided on was to allocate here as it was before (it has to happen somewhere before interning), and then call the intern function directly instead of going through the iteration-based approach. This should still only allocate the Vec<Kind> the once, but its an ugly bypass of the "right" interface.

Copy link
Member

@eddyb eddyb Oct 12, 2016

Choose a reason for hiding this comment

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

The tcx doesn't borrow the folder, it's copied out (I hope).
EDIT: I was wrong, TypeFolder has one less lifetime parameter than it'd need to avoid .tcx() resulting in a longer borrow 😢. This is fine for now, we'll try to solve this later.

folder.tcx().mk_substs(params)
}

fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
folder.fold_substs(self)
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.params.visit_with(visitor)
self.iter().any(|t| t.visit_with(visitor))
}
}

Expand All @@ -340,19 +328,19 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}

pub trait Subst<'tcx> : Sized {
fn subst<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
substs: &Substs<'tcx>) -> Self {
substs: &[Kind<'tcx>]) -> Self {
self.subst_spanned(tcx, substs, None)
}

fn subst_spanned<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
substs: &Substs<'tcx>,
substs: &[Kind<'tcx>],
span: Option<Span>)
-> Self;
}

impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
fn subst_spanned<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
substs: &Substs<'tcx>,
substs: &[Kind<'tcx>],
span: Option<Span>)
-> T
{
Expand All @@ -371,7 +359,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {

struct SubstFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
substs: &'a Substs<'tcx>,
substs: &'a [Kind<'tcx>],

// The location for which the substitution is performed, if available.
span: Option<Span>,
Expand Down Expand Up @@ -404,7 +392,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
// the specialized routine `ty::replace_late_regions()`.
match *r {
ty::ReEarlyBound(data) => {
let r = self.substs.params.get(data.index as usize)
let r = self.substs.get(data.index as usize)
.and_then(|k| k.as_region());
match r {
Some(r) => {
Expand Down Expand Up @@ -461,7 +449,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
// Look up the type in the substitutions. It really should be in there.
let opt_ty = self.substs.params.get(p.idx as usize)
let opt_ty = self.substs.get(p.idx as usize)
.and_then(|k| k.as_type());
let ty = match opt_ty {
Some(t) => t,
Expand All @@ -475,7 +463,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
source_ty,
p.idx,
self.root_ty,
self.substs.params);
self.substs);
}
};

Expand Down Expand Up @@ -552,7 +540,7 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> {
-> ty::TraitRef<'tcx> {
let defs = tcx.lookup_generics(trait_id);

let params = substs.params[..defs.own_count()].iter().cloned();
let params = substs[..defs.own_count()].iter().cloned();
ty::TraitRef {
def_id: trait_id,
substs: Substs::new(tcx, params)
Expand All @@ -567,7 +555,7 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> {
// Assert there is a Self.
trait_ref.substs.type_at(0);

let params = trait_ref.substs.params[1..].iter().cloned();
let params = trait_ref.substs[1..].iter().cloned();
ty::ExistentialTraitRef {
def_id: trait_ref.def_id,
substs: Substs::new(tcx, params)
Expand All @@ -587,7 +575,7 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> {
assert!(!self_ty.has_escaping_regions());

self.map_bound(|trait_ref| {
let params = trait_ref.substs.params.iter().cloned();
let params = trait_ref.substs.iter().cloned();
let params = iter::once(Kind::from(self_ty)).chain(params);
ty::TraitRef {
def_id: trait_ref.def_id,
Expand Down
Loading