diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index be4139e65ba..d1d81b9a915 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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, diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index b986d4dd591..c322b4aae7e 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -112,8 +112,8 @@ impl Substs { r: Vec) -> 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, @@ -121,8 +121,8 @@ impl Substs { 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) -> Substs @@ -226,21 +226,23 @@ 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, } } @@ -248,7 +250,8 @@ impl ParamSpace { match u { 0 => TypeSpace, 1 => SelfSpace, - 2 => FnSpace, + 2 => AssocSpace, + 3 => FnSpace, _ => panic!("Invalid ParamSpace: {}", u) } } @@ -268,11 +271,13 @@ pub struct VecPerParamSpace { // 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, } @@ -292,7 +297,8 @@ impl VecPerParamSpace { 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()), } } @@ -300,6 +306,7 @@ impl VecPerParamSpace { VecPerParamSpace { type_limit: 0, self_limit: 0, + assoc_limit: 0, content: Vec::new() } } @@ -310,26 +317,33 @@ impl VecPerParamSpace { /// `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, s: Vec, f: Vec) -> VecPerParamSpace { + pub fn new(t: Vec, s: Vec, a: Vec, f: Vec) -> VecPerParamSpace { 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, type_limit: uint, self_limit: uint) + fn new_internal(content: Vec, type_limit: uint, self_limit: uint, assoc_limit: uint) -> VecPerParamSpace { VecPerParamSpace { type_limit: type_limit, self_limit: self_limit, + assoc_limit: assoc_limit, content: content, } } @@ -341,9 +355,10 @@ impl VecPerParamSpace { 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); } @@ -354,9 +369,10 @@ impl VecPerParamSpace { 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) } @@ -442,35 +458,29 @@ impl VecPerParamSpace { 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(self, pred: |T| -> U) -> VecPerParamSpace { - 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, Vec, Vec) { - // 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, Vec, Vec, Vec) { + let VecPerParamSpace { type_limit, self_limit, assoc_limit, content } = self; - let mut i = 0; - let (type_vec, self_vec) = prefix.partition(|_| { - let on_left = i < type_limit; - i += 1; - on_left - }); + let mut content_iter = content.into_iter(); - (type_vec, self_vec, fn_vec) + 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(); + + (types, selfs, assocs, fns) } pub fn with_vec(mut self, space: ParamSpace, vec: Vec) @@ -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()); } } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f8c1c37452b..a665e1f0a26 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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 } } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index db433167298..e54d50c8b5f 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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 @@ -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, @@ -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); @@ -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) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8befba00fd2..1d769572ffe 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -666,10 +666,11 @@ impl Repr for subst::Substs { impl Repr for subst::VecPerParamSpace { 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)) } } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index fa38482b21c..48813ff142c 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -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 @@ -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), @@ -32,7 +32,7 @@ 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, } @@ -40,7 +40,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] // 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), } @@ -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), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index c049fbc0fed..0e8e52df456 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -13,29 +13,29 @@ // Try enums too. #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[];[]] f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[];[]] f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[];[]] f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index c61f2ff79c0..c576c5e2edd 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -19,7 +19,7 @@ use std::mem; trait T { fn foo(); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[[-];[];[]] +struct TOption<'a> { //~ ERROR regions=[[-];[];[];[]] v: Option>, }