Skip to content

Commit

Permalink
Add a 4th space for associated types defined in a trait (currently un…
Browse files Browse the repository at this point in the history
…used)
  • Loading branch information
nikomatsakis committed Nov 3, 2014
1 parent 94d142b commit d2f8074
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 69 deletions.
3 changes: 2 additions & 1 deletion src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,9 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
{
let types = self.read_to_vec(|this| Ok(f(this))).unwrap();
let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap();
let assocs = self.read_to_vec(|this| Ok(f(this))).unwrap();
let fns = self.read_to_vec(|this| Ok(f(this))).unwrap();
VecPerParamSpace::new(types, selfs, fns)
VecPerParamSpace::new(types, selfs, assocs, fns)
}

fn read_vtable_res_with_key(&mut self,
Expand Down
101 changes: 56 additions & 45 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,17 @@ impl Substs {
r: Vec<ty::Region>)
-> Substs
{
Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()),
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new(), Vec::new()),
VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
}

pub fn new_trait(t: Vec<ty::t>,
r: Vec<ty::Region>,
s: ty::t)
-> Substs
{
Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()),
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new(), Vec::new()),
VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
}

pub fn erased(t: VecPerParamSpace<ty::t>) -> Substs
Expand Down Expand Up @@ -226,29 +226,32 @@ impl RegionSubsts {
#[deriving(PartialOrd, Ord, PartialEq, Eq,
Clone, Hash, Encodable, Decodable, Show)]
pub enum ParamSpace {
TypeSpace, // Type parameters attached to a type definition, trait, or impl
SelfSpace, // Self parameter on a trait
FnSpace, // Type parameters attached to a method or fn
TypeSpace, // Type parameters attached to a type definition, trait, or impl
SelfSpace, // Self parameter on a trait
AssocSpace, // Assoc types defined in a trait/impl
FnSpace, // Type parameters attached to a method or fn
}

impl ParamSpace {
pub fn all() -> [ParamSpace, ..3] {
[TypeSpace, SelfSpace, FnSpace]
pub fn all() -> [ParamSpace, ..4] {
[TypeSpace, SelfSpace, AssocSpace, FnSpace]
}

pub fn to_uint(self) -> uint {
match self {
TypeSpace => 0,
SelfSpace => 1,
FnSpace => 2,
AssocSpace => 2,
FnSpace => 3,
}
}

pub fn from_uint(u: uint) -> ParamSpace {
match u {
0 => TypeSpace,
1 => SelfSpace,
2 => FnSpace,
2 => AssocSpace,
3 => FnSpace,
_ => panic!("Invalid ParamSpace: {}", u)
}
}
Expand All @@ -268,11 +271,13 @@ pub struct VecPerParamSpace<T> {
// Here is how the representation corresponds to the abstraction
// i.e. the "abstraction function" AF:
//
// AF(self) = (self.content.slice_to(self.type_limit),
// self.content.slice(self.type_limit, self.self_limit),
// self.content.slice_from(self.self_limit))
// AF(self) = (self.content[..self.type_limit],
// self.content[self.type_limit..self.self_limit],
// self.content[self.self_limit..self.assoc_limit],
// self.content[self.assoc_limit..])
type_limit: uint,
self_limit: uint,
assoc_limit: uint,
content: Vec<T>,
}

Expand All @@ -292,14 +297,16 @@ impl<T> VecPerParamSpace<T> {
match space {
TypeSpace => (0, self.type_limit),
SelfSpace => (self.type_limit, self.self_limit),
FnSpace => (self.self_limit, self.content.len()),
AssocSpace => (self.self_limit, self.assoc_limit),
FnSpace => (self.assoc_limit, self.content.len()),
}
}

pub fn empty() -> VecPerParamSpace<T> {
VecPerParamSpace {
type_limit: 0,
self_limit: 0,
assoc_limit: 0,
content: Vec::new()
}
}
Expand All @@ -310,26 +317,33 @@ impl<T> VecPerParamSpace<T> {

/// `t` is the type space.
/// `s` is the self space.
/// `a` is the assoc space.
/// `f` is the fn space.
pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
pub fn new(t: Vec<T>, s: Vec<T>, a: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
let type_limit = t.len();
let self_limit = t.len() + s.len();
let self_limit = type_limit + s.len();
let assoc_limit = self_limit + a.len();

let mut content = t;
content.extend(s.into_iter());
content.extend(a.into_iter());
content.extend(f.into_iter());

VecPerParamSpace {
type_limit: type_limit,
self_limit: self_limit,
assoc_limit: assoc_limit,
content: content,
}
}

fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint)
fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint, assoc_limit: uint)
-> VecPerParamSpace<T>
{
VecPerParamSpace {
type_limit: type_limit,
self_limit: self_limit,
assoc_limit: assoc_limit,
content: content,
}
}
Expand All @@ -341,9 +355,10 @@ impl<T> VecPerParamSpace<T> {
pub fn push(&mut self, space: ParamSpace, value: T) {
let (_, limit) = self.limits(space);
match space {
TypeSpace => { self.type_limit += 1; self.self_limit += 1; }
SelfSpace => { self.self_limit += 1; }
FnSpace => {}
TypeSpace => { self.type_limit += 1; self.self_limit += 1; self.assoc_limit += 1; }
SelfSpace => { self.self_limit += 1; self.assoc_limit += 1; }
AssocSpace => { self.assoc_limit += 1; }
FnSpace => { }
}
self.content.insert(limit, value);
}
Expand All @@ -354,9 +369,10 @@ impl<T> VecPerParamSpace<T> {
None
} else {
match space {
TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; }
SelfSpace => { self.self_limit -= 1; }
FnSpace => {}
TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; self.assoc_limit -= 1; }
SelfSpace => { self.self_limit -= 1; self.assoc_limit -= 1; }
AssocSpace => { self.assoc_limit -= 1; }
FnSpace => {}
}
self.content.remove(limit - 1)
}
Expand Down Expand Up @@ -442,35 +458,29 @@ impl<T> VecPerParamSpace<T> {
let result = self.iter().map(pred).collect();
VecPerParamSpace::new_internal(result,
self.type_limit,
self.self_limit)
self.self_limit,
self.assoc_limit)
}

pub fn map_move<U>(self, pred: |T| -> U) -> VecPerParamSpace<U> {
let (t, s, f) = self.split();
let (t, s, a, f) = self.split();
VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(),
s.into_iter().map(|p| pred(p)).collect(),
a.into_iter().map(|p| pred(p)).collect(),
f.into_iter().map(|p| pred(p)).collect())
}

pub fn split(self) -> (Vec<T>, Vec<T>, Vec<T>) {
// FIXME (#15418): this does two traversals when in principle
// one would suffice. i.e. change to use `move_iter`.
let VecPerParamSpace { type_limit, self_limit, content } = self;
let mut i = 0;
let (prefix, fn_vec) = content.partition(|_| {
let on_left = i < self_limit;
i += 1;
on_left
});
pub fn split(self) -> (Vec<T>, Vec<T>, Vec<T>, Vec<T>) {
let VecPerParamSpace { type_limit, self_limit, assoc_limit, content } = self;

let mut content_iter = content.into_iter();

let mut i = 0;
let (type_vec, self_vec) = prefix.partition(|_| {
let on_left = i < type_limit;
i += 1;
on_left
});
let types = content_iter.by_ref().take(type_limit).collect();
let selfs = content_iter.by_ref().take(self_limit - type_limit).collect();
let assocs = content_iter.by_ref().take(assoc_limit - self_limit).collect();
let fns = content_iter.collect();

(type_vec, self_vec, fn_vec)
(types, selfs, assocs, fns)
}

pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
Expand Down Expand Up @@ -616,12 +626,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
this.tcx().sess.span_bug(
span,
format!("Type parameter `{}` ({}/{}/{}) out of range \
when substituting (root type={})",
when substituting (root type={}) substs={}",
p.repr(this.tcx()),
source_ty.repr(this.tcx()),
space,
index,
this.root_ty.repr(this.tcx())).as_slice());
this.root_ty.repr(this.tcx()),
this.substs.repr(this.tcx())).as_slice());
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1607,7 +1607,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(o) => o,
Err(ErrorReported) => Vec::new()
};
let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new());
let obligations = VecPerParamSpace::new(obligations, Vec::new(),
Vec::new(), Vec::new());
VtableBuiltinData { nested: obligations }
}

Expand Down
12 changes: 7 additions & 5 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ pub fn trans_static_method_callee(bcx: Block,
// type parameters that belong to the trait but also some that
// belong to the method:
let rcvr_substs = node_id_substs(bcx, ExprId(expr_id));
let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.split();
let (rcvr_type, rcvr_self, rcvr_assoc, rcvr_method) = rcvr_substs.types.split();

// Lookup the precise impl being called. To do that, we need to
// create a trait reference identifying the self type and other
Expand All @@ -232,6 +232,7 @@ pub fn trans_static_method_callee(bcx: Block,
let trait_substs =
Substs::erased(VecPerParamSpace::new(rcvr_type,
rcvr_self,
rcvr_assoc,
Vec::new()));
debug!("trait_substs={}", trait_substs.repr(bcx.tcx()));
let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id,
Expand Down Expand Up @@ -265,10 +266,11 @@ pub fn trans_static_method_callee(bcx: Block,
// that with the `rcvr_method` from before, which tells us
// the type parameters from the *method*, to yield
// `callee_substs=[[T=int],[],[U=String]]`.
let (impl_type, impl_self, _) = impl_substs.types.split();
let (impl_type, impl_self, impl_assoc, _) = impl_substs.types.split();
let callee_substs =
Substs::erased(VecPerParamSpace::new(impl_type,
impl_self,
impl_assoc,
rcvr_method));

let mth_id = method_with_name(ccx, impl_did, mname);
Expand Down Expand Up @@ -397,12 +399,12 @@ fn combine_impl_and_methods_tps(bcx: Block,

// Break apart the type parameters from the node and type
// parameters from the receiver.
let (_, _, node_method) = node_substs.types.split();
let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.clone().split();
let (_, _, _, node_method) = node_substs.types.split();
let (rcvr_type, rcvr_self, rcvr_assoc, rcvr_method) = rcvr_substs.types.clone().split();
assert!(rcvr_method.is_empty());
subst::Substs {
regions: subst::ErasedRegions,
types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, rcvr_assoc, node_method)
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,10 +666,11 @@ impl Repr for subst::Substs {

impl<T:Repr> Repr for subst::VecPerParamSpace<T> {
fn repr(&self, tcx: &ctxt) -> String {
format!("[{};{};{}]",
self.get_slice(subst::TypeSpace).repr(tcx),
self.get_slice(subst::SelfSpace).repr(tcx),
self.get_slice(subst::FnSpace).repr(tcx))
format!("[{};{};{};{}]",
self.get_slice(subst::TypeSpace).repr(tcx),
self.get_slice(subst::SelfSpace).repr(tcx),
self.get_slice(subst::AssocSpace).repr(tcx),
self.get_slice(subst::FnSpace).repr(tcx))
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/test/compile-fail/variance-regions-direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// Regions that just appear in normal spots are contravariant:

#[rustc_variance]
struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]]
struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[];[]]
x: &'a int,
y: &'b [int],
c: &'c str
Expand All @@ -23,7 +23,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]]
// Those same annotations in function arguments become covariant:

#[rustc_variance]
struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]]
struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[];[]]
x: extern "Rust" fn(&'a int),
y: extern "Rust" fn(&'b [int]),
c: extern "Rust" fn(&'c str),
Expand All @@ -32,15 +32,15 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]]
// Mutability induces invariance:

#[rustc_variance]
struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]]
struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[];[]]
x: &'a mut &'b int,
}

// Mutability induces invariance, even when in a
// contravariant context:

#[rustc_variance]
struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]]
struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[];[]]
x: extern "Rust" fn(&'a mut &'b int),
}

Expand All @@ -50,21 +50,21 @@ struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]]
// argument list occurs in an invariant context.

#[rustc_variance]
struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[]]
struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[];[]]
x: &'a mut extern "Rust" fn(&'b int),
}

// No uses at all is bivariant:

#[rustc_variance]
struct Test7<'a> { //~ ERROR regions=[[*];[];[]]
struct Test7<'a> { //~ ERROR regions=[[*];[];[];[]]
x: int
}

// Try enums too.

#[rustc_variance]
enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]]
enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]]
Test8A(extern "Rust" fn(&'a int)),
Test8B(&'b [int]),
Test8C(&'b mut &'c str),
Expand Down

0 comments on commit d2f8074

Please sign in to comment.