diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3d2bd763a1434..d1d81b9a915cc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -81,7 +81,7 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, e::IIForeignRef(i) => i.id, e::IITraitItemRef(_, &ast::ProvidedMethod(ref m)) => m.id, e::IITraitItemRef(_, &ast::RequiredMethod(ref m)) => m.id, - e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.id, + e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.ty_param.id, e::IIImplItemRef(_, &ast::MethodImplItem(ref m)) => m.id, e::IIImplItemRef(_, &ast::TypeImplItem(ref ti)) => ti.id, }; @@ -156,7 +156,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, match *ti { ast::ProvidedMethod(ref m) => m.pe_ident(), ast::RequiredMethod(ref ty_m) => ty_m.ident, - ast::TypeTraitItem(ref ti) => ti.ident, + ast::TypeTraitItem(ref ti) => ti.ty_param.ident, } }, ast::IIImplItem(_, ref m) => { @@ -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/privacy.rs b/src/librustc/middle/privacy.rs index 2256bd71e652c..4fbffa2a819d5 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -296,8 +296,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.exported_items.insert(m.id); } ast::TypeTraitItem(ref t) => { - debug!("typedef {}", t.id); - self.exported_items.insert(t.id); + debug!("typedef {}", t.ty_param.id); + self.exported_items.insert(t.ty_param.id); } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index c297bdc6ca2e7..d1345efaf90d8 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1559,19 +1559,19 @@ impl<'a> Resolver<'a> { } ast::TypeTraitItem(ref associated_type) => { let def = DefAssociatedTy(local_def( - associated_type.id)); + associated_type.ty_param.id)); let name_bindings = - self.add_child(associated_type.ident.name, + self.add_child(associated_type.ty_param.ident.name, module_parent.clone(), ForbidDuplicateTypesAndValues, - associated_type.span); + associated_type.ty_param.span); // NB: not IMPORTABLE name_bindings.define_type(def, - associated_type.span, + associated_type.ty_param.span, PUBLIC); - (associated_type.ident.name, TypeTraitItemKind) + (associated_type.ty_param.ident.name, TypeTraitItemKind) } }; @@ -4218,7 +4218,7 @@ impl<'a> Resolver<'a> { impl_items.as_slice()); } - ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => { + ItemTrait(ref generics, ref unbound, ref bounds, ref trait_items) => { // Create a new rib for the self type. let mut self_type_rib = Rib::new(ItemRibKind); @@ -4246,13 +4246,13 @@ impl<'a> Resolver<'a> { _ => {} } - for method in (*methods).iter() { - // Create a new rib for the method-specific type + for trait_item in (*trait_items).iter() { + // Create a new rib for the trait_item-specific type // parameters. // // FIXME #4951: Do we need a node ID here? - match *method { + match *trait_item { ast::RequiredMethod(ref ty_m) => { this.with_type_parameter_rib (HasTypeParameters(&ty_m.generics, @@ -4287,8 +4287,9 @@ impl<'a> Resolver<'a> { ProvidedMethod(m.id)), &**m) } - ast::TypeTraitItem(_) => { - visit::walk_trait_item(this, method); + ast::TypeTraitItem(ref data) => { + this.resolve_type_parameter(&data.ty_param); + visit::walk_trait_item(this, trait_item); } } } @@ -4477,20 +4478,25 @@ impl<'a> Resolver<'a> { fn resolve_type_parameters(&mut self, type_parameters: &OwnedSlice) { for type_parameter in type_parameters.iter() { - for bound in type_parameter.bounds.iter() { - self.resolve_type_parameter_bound(type_parameter.id, bound, - TraitBoundingTypeParameter); - } - match &type_parameter.unbound { - &Some(ref unbound) => - self.resolve_type_parameter_bound( - type_parameter.id, unbound, TraitBoundingTypeParameter), - &None => {} - } - match type_parameter.default { - Some(ref ty) => self.resolve_type(&**ty), - None => {} - } + self.resolve_type_parameter(type_parameter); + } + } + + fn resolve_type_parameter(&mut self, + type_parameter: &TyParam) { + for bound in type_parameter.bounds.iter() { + self.resolve_type_parameter_bound(type_parameter.id, bound, + TraitBoundingTypeParameter); + } + match &type_parameter.unbound { + &Some(ref unbound) => + self.resolve_type_parameter_bound( + type_parameter.id, unbound, TraitBoundingTypeParameter), + &None => {} + } + match type_parameter.default { + Some(ref ty) => self.resolve_type(&**ty), + None => {} } } @@ -4577,14 +4583,14 @@ impl<'a> Resolver<'a> { self.resolve_error(trait_reference.path.span, format!("`{}` is not a trait", self.path_names_to_string( - &trait_reference.path))); + &trait_reference.path))); // If it's a typedef, give a note match def { DefTy(..) => { self.session.span_note( - trait_reference.path.span, - format!("`type` aliases cannot \ + trait_reference.path.span, + format!("`type` aliases cannot \ be used for traits") .as_slice()); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9cac97dc65941..7f6a73c83fa76 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -86,7 +86,7 @@ impl<'v> Visitor<'v> for Annotator { } } - TypeTraitItem(ref typedef) => (typedef.id, &typedef.attrs), + TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs), }; self.annotate(id, attrs, |v| visit::walk_trait_item(v, t)); } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index b986d4dd591f3..a7120080eed3b 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -112,17 +112,18 @@ 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, r: Vec, + a: Vec, 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), a, Vec::new()), + VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new())) } pub fn erased(t: VecPerParamSpace) -> Substs @@ -226,21 +227,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 +251,8 @@ impl ParamSpace { match u { 0 => TypeSpace, 1 => SelfSpace, - 2 => FnSpace, + 2 => AssocSpace, + 3 => FnSpace, _ => panic!("Invalid ParamSpace: {}", u) } } @@ -268,14 +272,27 @@ 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, } +/** + * The `split` function converts one `VecPerParamSpace` into this + * `SeparateVecsPerParamSpace` structure. + */ +pub struct SeparateVecsPerParamSpace { + pub types: Vec, + pub selfs: Vec, + pub assocs: Vec, + pub fns: Vec, +} + impl fmt::Show for VecPerParamSpace { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "VecPerParamSpace {{")); @@ -292,7 +309,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 +318,7 @@ impl VecPerParamSpace { VecPerParamSpace { type_limit: 0, self_limit: 0, + assoc_limit: 0, content: Vec::new() } } @@ -310,26 +329,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 +367,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 +381,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 +470,35 @@ 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 SeparateVecsPerParamSpace { + types: t, + selfs: s, + assocs: a, + fns: 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) -> SeparateVecsPerParamSpace { + 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) + SeparateVecsPerParamSpace { + types: content_iter.by_ref().take(type_limit).collect(), + selfs: content_iter.by_ref().take(self_limit - type_limit).collect(), + assocs: content_iter.by_ref().take(assoc_limit - self_limit).collect(), + fns: content_iter.collect() + } } pub fn with_vec(mut self, space: ParamSpace, vec: Vec) @@ -616,12 +644,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 f8c1c37452b38..abc36359a8564 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 } } @@ -1682,6 +1683,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![arguments_tuple.subst(self.tcx(), substs), new_signature.output.unwrap().subst(self.tcx(), substs)], vec![], + vec![], obligation.self_ty()) }); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index db433167298ce..fbd4db959ce0c 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -205,7 +205,12 @@ 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 subst::SeparateVecsPerParamSpace { + types: rcvr_type, + selfs: rcvr_self, + assocs: rcvr_assoc, + fns: 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 +237,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 +271,16 @@ 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 subst::SeparateVecsPerParamSpace { + types: impl_type, + selfs: impl_self, + assocs: impl_assoc, + fns: _ + } = 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 +409,17 @@ 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().fns; + let subst::SeparateVecsPerParamSpace { + types: rcvr_type, + selfs: rcvr_self, + assocs: rcvr_assoc, + fns: 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/middle/ty.rs b/src/librustc/middle/ty.rs index b9af31665a113..8211fec505b9f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -573,10 +573,6 @@ pub struct ctxt<'tcx> { /// Maps def IDs to true if and only if they're associated types. pub associated_types: RefCell>, - /// Maps def IDs of traits to information about their associated types. - pub trait_associated_types: - RefCell>>>, - /// Caches the results of trait selection. This cache is used /// for things that do not have to do with the parameters in scope. pub selection_cache: traits::SelectionCache, @@ -1564,7 +1560,6 @@ pub fn mk_ctxt<'tcx>(s: Session, stability: RefCell::new(stability), capture_modes: capture_modes, associated_types: RefCell::new(DefIdMap::new()), - trait_associated_types: RefCell::new(DefIdMap::new()), selection_cache: traits::SelectionCache::new(), repr_hint_cache: RefCell::new(DefIdMap::new()), } @@ -1994,6 +1989,16 @@ impl ItemSubsts { } } +impl ParamBounds { + pub fn empty() -> ParamBounds { + ParamBounds { + builtin_bounds: empty_builtin_bounds(), + trait_bounds: Vec::new(), + region_bounds: Vec::new(), + } + } +} + // Type utilities pub fn type_is_nil(ty: t) -> bool { @@ -4155,18 +4160,6 @@ impl Ord for AssociatedTypeInfo { } } -/// Returns the associated types belonging to the given trait, in parameter -/// order. -pub fn associated_types_for_trait(cx: &ctxt, trait_id: ast::DefId) - -> Rc> { - cx.trait_associated_types - .borrow() - .find(&trait_id) - .expect("associated_types_for_trait(): trait not found, try calling \ - ensure_associated_types()") - .clone() -} - pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId) -> Rc> { lookup_locally_or_in_crate_store("trait_item_def_ids", diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 66d4f73eacc87..951ac795d80b2 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -54,7 +54,7 @@ use middle::def; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; use middle::lang_items::{FnOnceTraitLangItem}; use middle::resolve_lifetime as rl; -use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; +use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; use middle::ty; use middle::typeck::lookup_def_tcx; @@ -215,7 +215,8 @@ fn ast_path_substs<'tcx,AC,RS>( associated_ty: Option, path: &ast::Path) -> Substs - where AC: AstConv<'tcx>, RS: RegionScope { + where AC: AstConv<'tcx>, RS: RegionScope +{ /*! * Given a path `path` that refers to an item `I` with the * declared generics `decl_generics`, returns an appropriate @@ -338,17 +339,21 @@ fn ast_path_substs<'tcx,AC,RS>( substs.types.push(TypeSpace, default); } None => { - // This is an associated type. - substs.types.push( - TypeSpace, - this.associated_type_binding(path.span, - associated_ty, - decl_def_id, - param.def_id)) + tcx.sess.span_bug(path.span, + "extra parameter without default"); } } } + for param in decl_generics.types.get_slice(AssocSpace).iter() { + substs.types.push( + AssocSpace, + this.associated_type_binding(path.span, + associated_ty, + decl_def_id, + param.def_id)) + } + substs } @@ -628,9 +633,13 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( a_seq_ty: &ast::Ty, ptr_ty: PointerTy, constr: |ty::t| -> ty::t) - -> ty::t { + -> ty::t +{ let tcx = this.tcx(); - debug!("mk_pointer(ptr_ty={})", ptr_ty); + + debug!("mk_pointer(ptr_ty={}, a_seq_ty={})", + ptr_ty, + a_seq_ty.repr(tcx)); match a_seq_ty.node { ast::TyVec(ref ty) => { @@ -730,7 +739,13 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, trait_type_id: ast::DefId, span: Span) -> ty::t - where AC: AstConv<'tcx>, RS: RegionScope { + where AC: AstConv<'tcx>, RS: RegionScope +{ + debug!("associated_ty_to_ty(trait_path={}, for_ast_type={}, trait_type_id={})", + trait_path.repr(this.tcx()), + for_ast_type.repr(this.tcx()), + trait_type_id.repr(this.tcx())); + // Find the trait that this associated type belongs to. let trait_did = match ty::impl_or_trait_item(this.tcx(), trait_type_id).container() { @@ -757,9 +772,16 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, None, Some(for_type), trait_path); + + debug!("associated_ty_to_ty(trait_ref={})", + trait_ref.repr(this.tcx())); + let trait_def = this.get_trait_def(trait_did); for type_parameter in trait_def.generics.types.iter() { if type_parameter.def_id == trait_type_id { + debug!("associated_ty_to_ty(type_parameter={} substs={})", + type_parameter.repr(this.tcx()), + trait_ref.substs.repr(this.tcx())); return *trait_ref.substs.types.get(type_parameter.space, type_parameter.index) } @@ -772,7 +794,10 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, // Parses the programmer's textual representation of a type into our // internal notion of a type. pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { + this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t +{ + debug!("ast_ty_to_ty(ast_ty={})", + ast_ty.repr(this.tcx())); let tcx = this.tcx(); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 847d8e88bde88..863f09736ab27 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -298,13 +298,19 @@ fn collect_trait_methods(ccx: &CrateCtxt, &*m.pe_fn_decl()) } ast::TypeTraitItem(ref at) => { - tcx.sess.span_bug(at.span, + tcx.sess.span_bug(at.ty_param.span, "there shouldn't \ be a type trait \ item here") } }); + debug!("ty_method_of_trait_method yielded {} \ + for method {} of trait {}", + ty_method.repr(ccx.tcx), + trait_item.repr(ccx.tcx), + local_def(trait_id).repr(ccx.tcx)); + make_method_ty(ccx, &*ty_method); tcx.impl_or_trait_items @@ -315,9 +321,9 @@ fn collect_trait_methods(ccx: &CrateCtxt, ast::TypeTraitItem(ref ast_associated_type) => { let trait_did = local_def(trait_id); let associated_type = ty::AssociatedType { - name: ast_associated_type.ident.name, + name: ast_associated_type.ty_param.ident.name, vis: ast::Public, - def_id: local_def(ast_associated_type.id), + def_id: local_def(ast_associated_type.ty_param.id), container: TraitContainer(trait_did), }; @@ -345,7 +351,7 @@ fn collect_trait_methods(ccx: &CrateCtxt, method.id)) } ast::TypeTraitItem(ref typedef) => { - ty::TypeTraitItemId(local_def(typedef.id)) + ty::TypeTraitItemId(local_def(typedef.ty_param.id)) } } }).collect()); @@ -460,35 +466,35 @@ fn convert_associated_type(ccx: &CrateCtxt, // associated type. let type_parameter_def = trait_def.generics .types - .get_slice(subst::TypeSpace) + .get_slice(subst::AssocSpace) .iter() .find(|def| { - def.def_id == local_def(associated_type.id) + def.def_id == local_def(associated_type.ty_param.id) }); let type_parameter_def = match type_parameter_def { Some(type_parameter_def) => type_parameter_def, None => { - ccx.tcx().sess.span_bug(associated_type.span, + ccx.tcx().sess.span_bug(associated_type.ty_param.span, "`convert_associated_type()` didn't find \ a type parameter ID corresponding to \ this type") } }; let param_type = ty::mk_param(ccx.tcx, - subst::TypeSpace, + type_parameter_def.space, type_parameter_def.index, - local_def(associated_type.id)); - ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.id), + local_def(associated_type.ty_param.id)); + ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.ty_param.id), Polytype { generics: ty::Generics::empty(), ty: param_type, }); - write_ty_to_tcx(ccx.tcx, associated_type.id, param_type); + write_ty_to_tcx(ccx.tcx, associated_type.ty_param.id, param_type); let associated_type = Rc::new(ty::AssociatedType { - name: associated_type.ident.name, + name: associated_type.ty_param.ident.name, vis: ast::Public, - def_id: local_def(associated_type.id), + def_id: local_def(associated_type.ty_param.id), container: TraitContainer(trait_def.trait_ref.def_id), }); ccx.tcx @@ -780,25 +786,18 @@ impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { ty: Option, trait_id: ast::DefId, associated_type_id: ast::DefId) - -> ty::t { - ensure_associated_types(self, trait_id); - let associated_type_ids = ty::associated_types_for_trait(self.ccx.tcx, - trait_id); + -> ty::t + { + let trait_def = ty::lookup_trait_def(self.tcx(), trait_id); match self.opt_trait_ref_id { Some(trait_ref_id) if trait_ref_id == trait_id => { // It's an associated type on the trait that we're // implementing. - let associated_type_id = - associated_type_ids.iter() - .find(|id| { - id.def_id == associated_type_id - }) - .expect("associated_type_binding(): \ - expected associated type ID \ - in trait"); - let associated_type = - ty::impl_or_trait_item(self.ccx.tcx, - associated_type_id.def_id); + assert!(trait_def.generics.types + .get_slice(subst::AssocSpace) + .iter() + .any(|type_param_def| type_param_def.def_id == associated_type_id)); + let associated_type = ty::impl_or_trait_item(self.ccx.tcx, associated_type_id); for impl_item in self.impl_items.iter() { match *impl_item { ast::MethodImplItem(_) => {} @@ -978,9 +977,9 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { match *item { ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} ast::TypeTraitItem(ref item) => { - if local_def(item.id) == associated_type_id { + if local_def(item.ty_param.id) == associated_type_id { return ty::mk_param(self.tcx(), - subst::TypeSpace, + subst::AssocSpace, index, associated_type_id) } @@ -1451,7 +1450,8 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { trait_id: ast::NodeId, generics: &ast::Generics, items: &[ast::TraitItem]) - -> subst::Substs { + -> subst::Substs + { // Creates a no-op substitution for the trait's type parameters. let regions = generics.lifetimes @@ -1464,7 +1464,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { .collect(); // Start with the generics in the type parameters... - let mut types: Vec<_> = + let types: Vec<_> = generics.ty_params .iter() .enumerate() @@ -1472,24 +1472,27 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { i, local_def(def.id))) .collect(); - // ...and add generics synthesized from the associated types. - for item in items.iter() { - match *item { + // ...and also create generics synthesized from the associated types. + let assoc_types: Vec<_> = + items.iter() + .flat_map(|item| match *item { ast::TypeTraitItem(ref trait_item) => { let index = types.len(); - types.push(ty::mk_param(ccx.tcx, - subst::TypeSpace, - index, - local_def(trait_item.id))) + Some(ty::mk_param(ccx.tcx, + subst::AssocSpace, + index, + local_def(trait_item.ty_param.id))).into_iter() } - ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} - } - } + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { + None.into_iter() + } + }) + .collect(); let self_ty = ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id)); - subst::Substs::new_trait(types, regions, self_ty) + subst::Substs::new_trait(types, regions, assoc_types, self_ty) } } @@ -1630,11 +1633,11 @@ fn ty_of_trait_item(ccx: &CrateCtxt, trait_item: &ast::TraitItem) "ty_of_trait_item() on provided method") } ast::TypeTraitItem(ref associated_type) => { - let parent = ccx.tcx.map.get_parent(associated_type.id); + let parent = ccx.tcx.map.get_parent(associated_type.ty_param.id); let trait_def = match ccx.tcx.map.get(parent) { ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), _ => { - ccx.tcx.sess.span_bug(associated_type.span, + ccx.tcx.sess.span_bug(associated_type.ty_param.span, "associated type's parent wasn't \ an item?!") } @@ -1661,38 +1664,33 @@ fn ty_generics_for_type(ccx: &CrateCtxt, fn ty_generics_for_trait(ccx: &CrateCtxt, trait_id: ast::NodeId, substs: &subst::Substs, - generics: &ast::Generics, + ast_generics: &ast::Generics, items: &[ast::TraitItem]) -> ty::Generics { let mut generics = ty_generics(ccx, subst::TypeSpace, - generics.lifetimes.as_slice(), - generics.ty_params.as_slice(), + ast_generics.lifetimes.as_slice(), + ast_generics.ty_params.as_slice(), ty::Generics::empty(), - &generics.where_clause, + &ast_generics.where_clause, DontCreateTypeParametersForAssociatedTypes); // Add in type parameters for any associated types. for item in items.iter() { match *item { ast::TypeTraitItem(ref associated_type) => { - let def = ty::TypeParameterDef { - space: subst::TypeSpace, - index: generics.types.len(subst::TypeSpace), - name: associated_type.ident.name, - def_id: local_def(associated_type.id), - bounds: ty::ParamBounds { - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: Vec::new(), - region_bounds: Vec::new(), - }, - associated_with: Some(local_def(trait_id)), - default: None, - }; - ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.id, + let def = + get_or_create_type_parameter_def( + ccx, + subst::AssocSpace, + &associated_type.ty_param, + generics.types.len(subst::TypeSpace), + &ast_generics.where_clause, + Some(local_def(trait_id))); + ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id, def.clone()); - generics.types.push(subst::TypeSpace, def); + generics.types.push(subst::AssocSpace, def); } ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {} } @@ -1791,86 +1789,17 @@ enum CreateTypeParametersForAssociatedTypesFlag { CreateTypeParametersForAssociatedTypes, } -fn ensure_associated_types<'tcx,AC>(this: &AC, trait_id: ast::DefId) - where AC: AstConv<'tcx> { - if this.tcx().trait_associated_types.borrow().contains_key(&trait_id) { - return - } - - if trait_id.krate == ast::LOCAL_CRATE { - match this.tcx().map.find(trait_id.node) { - Some(ast_map::NodeItem(item)) => { - match item.node { - ast::ItemTrait(_, _, _, ref trait_items) => { - let mut result = Vec::new(); - let mut index = 0; - for trait_item in trait_items.iter() { - match *trait_item { - ast::RequiredMethod(_) | - ast::ProvidedMethod(_) => {} - ast::TypeTraitItem(ref associated_type) => { - let info = ty::AssociatedTypeInfo { - def_id: local_def(associated_type.id), - index: index, - name: associated_type.ident.name, - }; - result.push(info); - index += 1; - } - } - } - this.tcx() - .trait_associated_types - .borrow_mut() - .insert(trait_id, Rc::new(result)); - return - } - _ => { - this.tcx().sess.bug("ensure_associated_types() \ - called on non-trait") - } - } - } - _ => { - this.tcx().sess.bug("ensure_associated_types() called on \ - non-trait") - } - } - - } - - // Cross-crate case. - let mut result = Vec::new(); - let mut index = 0; - let trait_items = ty::trait_items(this.tcx(), trait_id); - for trait_item in trait_items.iter() { - match *trait_item { - ty::MethodTraitItem(_) => {} - ty::TypeTraitItem(ref associated_type) => { - let info = ty::AssociatedTypeInfo { - def_id: associated_type.def_id, - index: index, - name: associated_type.name - }; - result.push(info); - index += 1; - } - } - } - this.tcx().trait_associated_types.borrow_mut().insert(trait_id, - Rc::new(result)); -} - fn ty_generics<'tcx,AC>(this: &AC, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], base_generics: ty::Generics, where_clause: &ast::WhereClause, - create_type_parameters_for_associated_types: + create_type_parameters_for_associated_types_flag: CreateTypeParametersForAssociatedTypesFlag) -> ty::Generics - where AC: AstConv<'tcx> { + where AC: AstConv<'tcx> +{ let mut result = base_generics; for (i, l) in lifetime_defs.iter().enumerate() { @@ -1891,62 +1820,11 @@ fn ty_generics<'tcx,AC>(this: &AC, // First, create the virtual type parameters for associated types if // necessary. let mut associated_types_generics = ty::Generics::empty(); - match create_type_parameters_for_associated_types { + match create_type_parameters_for_associated_types_flag { DontCreateTypeParametersForAssociatedTypes => {} CreateTypeParametersForAssociatedTypes => { - let mut index = 0; - for param in types.iter() { - for bound in param.bounds.iter() { - match *bound { - ast::TraitTyParamBound(ref trait_bound) => { - match lookup_def_tcx(this.tcx(), - trait_bound.path.span, - trait_bound.ref_id) { - def::DefTrait(trait_did) => { - ensure_associated_types(this, trait_did); - let associated_types = - ty::associated_types_for_trait( - this.tcx(), - trait_did); - for associated_type_info in - associated_types.iter() { - let associated_type_trait_item = - ty::impl_or_trait_item( - this.tcx(), - associated_type_info.def_id); - let def = ty::TypeParameterDef { - name: associated_type_trait_item.name(), - def_id: associated_type_info.def_id, - space: space, - index: types.len() + index, - bounds: ty::ParamBounds { - builtin_bounds: - ty::empty_builtin_bounds(), - trait_bounds: Vec::new(), - region_bounds: Vec::new(), - }, - associated_with: { - Some(local_def(param.id)) - }, - default: None, - }; - associated_types_generics.types - .push(space, - def); - index += 1; - } - } - _ => { - this.tcx().sess.span_bug(trait_bound.path - .span, - "not a trait?!") - } - } - } - _ => {} - } - } - } + create_type_parameters_for_associated_types(this, space, types, + &mut associated_types_generics); } } @@ -1960,7 +1838,8 @@ fn ty_generics<'tcx,AC>(this: &AC, space, param, i, - where_clause); + where_clause, + None); debug!("ty_generics: def for type param: {}, {}", def.repr(this.tcx()), space); @@ -1981,62 +1860,140 @@ fn ty_generics<'tcx,AC>(this: &AC, return result; - fn get_or_create_type_parameter_def<'tcx,AC>( - this: &AC, - space: subst::ParamSpace, - param: &ast::TyParam, - index: uint, - where_clause: &ast::WhereClause) - -> ty::TypeParameterDef - where AC: AstConv<'tcx> { - match this.tcx().ty_param_defs.borrow().find(¶m.id) { - Some(d) => { return (*d).clone(); } - None => { } + fn create_type_parameters_for_associated_types<'tcx,AC>( + this: &AC, + space: subst::ParamSpace, + types: &[ast::TyParam], + associated_types_generics: &mut ty::Generics) + where AC: AstConv<'tcx> + { + // The idea here is roughly as follows. We start with + // an item that is paramerized by various type parameters + // with bounds: + // + // fn foo(t: T) { ... } + // + // The traits in those bounds declare associated types: + // + // trait Iterator { type Elem; ... } + // + // And we rewrite the original function so that every associated + // type is bound to some fresh type parameter: + // + // fn foo>(t: T) { ... } + + // Number of synthetic type parameters created thus far + let mut index = 0; + + // Iterate over the each type parameter `T` (from the example) + for param in types.iter() { + // Iterate over the bound `Iterator` + for bound in param.bounds.iter() { + // In the above example, `ast_trait_ref` is `Iterator`. + let ast_trait_ref = match *bound { + ast::TraitTyParamBound(ref r) => r, + ast::UnboxedFnTyParamBound(..) => { continue; } + ast::RegionTyParamBound(..) => { continue; } + }; + + let trait_def_id = + match lookup_def_tcx(this.tcx(), + ast_trait_ref.path.span, + ast_trait_ref.ref_id) { + def::DefTrait(trait_def_id) => trait_def_id, + _ => { + this.tcx().sess.span_bug(ast_trait_ref.path.span, + "not a trait?!") + } + }; + + // trait_def_id is def-id of `Iterator` + let trait_def = ty::lookup_trait_def(this.tcx(), trait_def_id); + let associated_type_defs = trait_def.generics.types.get_slice(subst::AssocSpace); + + // Iterate over each associated type `Elem` + for associated_type_def in associated_type_defs.iter() { + // Create the fresh type parameter `A` + let def = ty::TypeParameterDef { + name: associated_type_def.name, + def_id: associated_type_def.def_id, + space: space, + index: types.len() + index, + bounds: ty::ParamBounds { + builtin_bounds: associated_type_def.bounds.builtin_bounds, + + // FIXME(#18178) -- we should add the other bounds, but + // that requires subst and more logic + trait_bounds: Vec::new(), + region_bounds: Vec::new(), + }, + associated_with: Some(local_def(param.id)), + default: None, + }; + associated_types_generics.types.push(space, def); + index += 1; + } + } } + } +} - let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); - let bounds = compute_bounds(this, - param.ident.name, - param_ty, - param.bounds.as_slice(), - ¶m.unbound, - param.span, - where_clause); - let default = match param.default { - None => None, - Some(ref path) => { - let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); - let cur_idx = index; - - ty::walk_ty(ty, |t| { - match ty::get(t).sty { - ty::ty_param(p) => if p.idx > cur_idx { +fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, + space: subst::ParamSpace, + param: &ast::TyParam, + index: uint, + where_clause: &ast::WhereClause, + associated_with: Option) + -> ty::TypeParameterDef + where AC: AstConv<'tcx> +{ + match this.tcx().ty_param_defs.borrow().find(¶m.id) { + Some(d) => { return (*d).clone(); } + None => { } + } + + let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); + let bounds = compute_bounds(this, + param.ident.name, + param_ty, + param.bounds.as_slice(), + ¶m.unbound, + param.span, + where_clause); + let default = match param.default { + None => None, + Some(ref path) => { + let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); + let cur_idx = index; + + ty::walk_ty(ty, |t| { + match ty::get(t).sty { + ty::ty_param(p) => if p.idx > cur_idx { span_err!(this.tcx().sess, path.span, E0128, "type parameters with a default cannot use \ forward declared identifiers"); }, _ => {} } - }); + }); - Some(ty) - } - }; + Some(ty) + } + }; - let def = ty::TypeParameterDef { - space: space, - index: index, - name: param.ident.name, - def_id: local_def(param.id), - associated_with: None, - bounds: bounds, - default: default - }; + let def = ty::TypeParameterDef { + space: space, + index: index, + name: param.ident.name, + def_id: local_def(param.id), + associated_with: associated_with, + bounds: bounds, + default: default + }; - this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); + this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); - def - } + def } fn compute_bounds<'tcx,AC>(this: &AC, diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 227a9b1bdcc88..55c3c23685357 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -774,10 +774,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { assert!(generics.regions.len(subst::FnSpace) == 0); let type_parameter_count = generics.types.len(subst::TypeSpace); + let type_parameters = self.next_ty_vars(type_parameter_count); + let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); - let type_parameters = self.next_ty_vars(type_parameter_count); - subst::Substs::new_trait(type_parameters, regions, self_ty) + + let assoc_type_parameter_count = generics.types.len(subst::AssocSpace); + let assoc_type_parameters = self.next_ty_vars(assoc_type_parameter_count); + + subst::Substs::new_trait(type_parameters, regions, assoc_type_parameters, self_ty) } pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region { @@ -791,7 +796,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn ty_to_string(&self, t: ty::t) -> String { ty_to_string(self.tcx, - self.resolve_type_vars_if_possible(t)) + self.resolve_type_vars_if_possible(t)) } pub fn tys_to_string(&self, ts: &[ty::t]) -> String { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8befba00fd2fe..c4f988580308f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -423,7 +423,13 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty), ty_err => "[type error]".to_string(), - ty_param(ref param_ty) => param_ty.repr(cx), + ty_param(ref param_ty) => { + if cx.sess.verbose() { + param_ty.repr(cx) + } else { + param_ty.user_string(cx) + } + } ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let base = ty::item_path_str(cx, did); let generics = ty::lookup_item_type(cx, did).generics; @@ -479,6 +485,17 @@ pub fn parameterized(cx: &ctxt, generics: &ty::Generics) -> String { + if cx.sess.verbose() { + if substs.is_noop() { + return format!("{}", base); + } else { + return format!("{}<{},{}>", + base, + substs.regions.repr(cx), + substs.types.repr(cx)); + } + } + let mut strs = Vec::new(); match substs.regions { @@ -503,7 +520,7 @@ pub fn parameterized(cx: &ctxt, let tps = substs.types.get_slice(subst::TypeSpace); let ty_params = generics.types.get_slice(subst::TypeSpace); let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some()); - let num_defaults = if has_defaults && !cx.sess.verbose() { + let num_defaults = if has_defaults { ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| { match def.default { Some(default) => default.subst(cx, substs) == actual, @@ -518,18 +535,6 @@ pub fn parameterized(cx: &ctxt, strs.push(ty_to_string(cx, *t)) } - if cx.sess.verbose() { - for t in substs.types.get_slice(subst::SelfSpace).iter() { - strs.push(format!("self {}", t.repr(cx))); - } - - // generally there shouldn't be any substs in the fn param - // space, but in verbose mode, print them out. - for t in substs.types.get_slice(subst::FnSpace).iter() { - strs.push(format!("fn {}", t.repr(cx))); - } - } - if strs.len() > 0u { format!("{}<{}>", base, strs.connect(", ")) } else { @@ -666,10 +671,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)) } } @@ -724,7 +730,7 @@ impl Repr for ty::TraitRef { fn repr(&self, tcx: &ctxt) -> String { let base = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - format!("<{} as {}>", + format!("<{} : {}>", self.substs.self_ty().repr(tcx), parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)) } @@ -739,6 +745,19 @@ impl Repr for ty::TraitDef { } } +impl Repr for ast::TraitItem { + fn repr(&self, _tcx: &ctxt) -> String { + match *self { + ast::RequiredMethod(ref data) => format!("RequiredMethod({}, id={})", + data.ident, data.id), + ast::ProvidedMethod(ref data) => format!("ProvidedMethod(id={})", + data.id), + ast::TypeTraitItem(ref data) => format!("TypeTraitItem({}, id={})", + data.ty_param.ident, data.ty_param.id), + } + } +} + impl Repr for ast::Expr { fn repr(&self, _tcx: &ctxt) -> String { format!("expr({}: {})", self.id, pprust::expr_to_string(self)) @@ -757,6 +776,12 @@ impl UserString for ast::Path { } } +impl Repr for ast::Ty { + fn repr(&self, _tcx: &ctxt) -> String { + format!("type({})", pprust::ty_to_string(self)) + } +} + impl Repr for ast::Item { fn repr(&self, tcx: &ctxt) -> String { format!("item({})", tcx.map.node_to_string(self.id)) @@ -1260,7 +1285,8 @@ impl UserString for ParamTy { impl Repr for ParamTy { fn repr(&self, tcx: &ctxt) -> String { - self.user_string(tcx) + let ident = self.user_string(tcx); + format!("{}/{}.{}", ident, self.space, self.idx) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c128588918e28..f96b3916f06de 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2203,12 +2203,12 @@ impl Clean for attr::Stability { impl Clean for ast::AssociatedType { fn clean(&self, cx: &DocContext) -> Item { Item { - source: self.span.clean(cx), - name: Some(self.ident.clean(cx)), + source: self.ty_param.span.clean(cx), + name: Some(self.ty_param.ident.clean(cx)), attrs: self.attrs.clean(cx), inner: AssociatedTypeItem, visibility: None, - def_id: ast_util::local_def(self.id), + def_id: ast_util::local_def(self.ty_param.id), stability: None, } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a2c859cf9fd3c..fdacc860bb766 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -861,10 +861,8 @@ pub enum ImplItem { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct AssociatedType { - pub id: NodeId, - pub span: Span, - pub ident: Ident, pub attrs: Vec, + pub ty_param: TyParam, } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index fa36577ebdb1f..f049b964ff33d 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -405,7 +405,9 @@ impl<'ast> Map<'ast> { MethMac(_) => panic!("no path elem for {}", node), } } - TypeTraitItem(ref m) => PathName(m.ident.name), + TypeTraitItem(ref m) => { + PathName(m.ty_param.ident.name) + } }, NodeVariant(v) => PathName(v.node.name.name), _ => panic!("no path elem for {}", node) @@ -510,7 +512,7 @@ impl<'ast> Map<'ast> { match *trait_method { RequiredMethod(ref type_method) => type_method.span, ProvidedMethod(ref method) => method.span, - TypeTraitItem(ref typedef) => typedef.span, + TypeTraitItem(ref typedef) => typedef.ty_param.span, } } Some(NodeImplItem(ref impl_item)) => { @@ -650,7 +652,7 @@ impl Named for TraitItem { match *self { RequiredMethod(ref tm) => tm.ident.name, ProvidedMethod(ref m) => m.name(), - TypeTraitItem(ref at) => at.ident.name, + TypeTraitItem(ref at) => at.ty_param.ident.name, } } } @@ -783,7 +785,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { self.insert(m.id, NodeTraitItem(tm)); } TypeTraitItem(ref typ) => { - self.insert(typ.id, NodeTraitItem(tm)); + self.insert(typ.ty_param.id, NodeTraitItem(tm)); } } } @@ -976,7 +978,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, let trait_item_id = match *trait_item { ProvidedMethod(ref m) => m.id, RequiredMethod(ref m) => m.id, - TypeTraitItem(ref ty) => ty.id, + TypeTraitItem(ref ty) => ty.ty_param.id, }; collector.insert(trait_item_id, NodeTraitItem(trait_item)); @@ -1080,7 +1082,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String { } TypeTraitItem(ref t) => { format!("type item {} in {} (id={})", - token::get_ident(t.ident), + token::get_ident(t.ty_param.ident), map.path_to_string(id), id) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 8b0e1f32fd4c9..035b80f5564e2 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -525,7 +525,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { match *tm { ast::RequiredMethod(ref m) => self.operation.visit_id(m.id), ast::ProvidedMethod(ref m) => self.operation.visit_id(m.id), - ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.id), + ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.ty_param.id), } visit::walk_trait_item(self, tm); } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c1877c827a41f..3743e08e9a936 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -260,7 +260,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} ast::TypeTraitItem(ref ti) => { self.gate_feature("associated_types", - ti.span, + ti.ty_param.span, "associated types are experimental") } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9a55f07e98d79..6535c8e89fd4e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -793,19 +793,16 @@ pub fn noop_fold_typedef(t: Typedef, folder: &mut T) pub fn noop_fold_associated_type(at: AssociatedType, folder: &mut T) -> AssociatedType - where T: Folder { - let new_id = folder.new_id(at.id); - let new_span = folder.new_span(at.span); - let new_ident = folder.fold_ident(at.ident); + where T: Folder +{ let new_attrs = at.attrs .iter() .map(|attr| folder.fold_attribute((*attr).clone())) .collect(); + let new_param = folder.fold_ty_param(at.ty_param); ast::AssociatedType { - ident: new_ident, attrs: new_attrs, - id: new_id, - span: new_span, + ty_param: new_param, } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index aa3b9668d4632..ad445ef331fe9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1229,16 +1229,13 @@ impl<'a> Parser<'a> { /// Parses `type Foo;` in a trait declaration only. The `type` keyword has /// already been parsed. fn parse_associated_type(&mut self, attrs: Vec) - -> AssociatedType { - let lo = self.span.lo; - let ident = self.parse_ident(); - let hi = self.span.hi; + -> AssociatedType + { + let ty_param = self.parse_ty_param(); self.expect(&token::Semi); AssociatedType { - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - ident: ident, attrs: attrs, + ty_param: ty_param, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 386fd8ae5a617..b7f6e65fb9367 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -818,9 +818,11 @@ impl<'a> State<'a> { } fn print_associated_type(&mut self, typedef: &ast::AssociatedType) - -> IoResult<()> { + -> IoResult<()> + { + try!(self.print_outer_attributes(typedef.attrs[])); try!(self.word_space("type")); - try!(self.print_ident(typedef.ident)); + try!(self.print_ty_param(&typedef.ty_param)); word(&mut self.s, ";") } @@ -2434,23 +2436,7 @@ impl<'a> State<'a> { } else { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); - match param.unbound { - Some(TraitTyParamBound(ref tref)) => { - try!(s.print_trait_ref(tref)); - try!(s.word_space("?")); - } - _ => {} - } - try!(s.print_ident(param.ident)); - try!(s.print_bounds(":", ¶m.bounds)); - match param.default { - Some(ref default) => { - try!(space(&mut s.s)); - try!(s.word_space("=")); - s.print_type(&**default) - } - _ => Ok(()) - } + s.print_ty_param(param) } })); @@ -2458,6 +2444,26 @@ impl<'a> State<'a> { Ok(()) } + pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { + match param.unbound { + Some(TraitTyParamBound(ref tref)) => { + try!(self.print_trait_ref(tref)); + try!(self.word_space("?")); + } + _ => {} + } + try!(self.print_ident(param.ident)); + try!(self.print_bounds(":", ¶m.bounds)); + match param.default { + Some(ref default) => { + try!(space(&mut self.s)); + try!(self.word_space("=")); + self.print_type(&**default) + } + _ => Ok(()) + } + } + pub fn print_where_clause(&mut self, generics: &ast::Generics) -> IoResult<()> { if generics.where_clause.predicates.len() == 0 { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bec72e88f99b9..86ee23d71a6b2 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -596,7 +596,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v Tr RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type), ProvidedMethod(ref method) => walk_method_helper(visitor, &**method), TypeTraitItem(ref associated_type) => { - visitor.visit_ident(associated_type.span, associated_type.ident) + visitor.visit_ident(associated_type.ty_param.span, + associated_type.ty_param.ident) } } } diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs new file mode 100644 index 0000000000000..47ab09d279f62 --- /dev/null +++ b/src/test/compile-fail/associated-types-unsized.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Sized? Value; + fn get(&self) -> ::Value; +} + +fn foo(t: T) { + let x = t.get(); //~ ERROR the trait `core::kinds::Sized` is not implemented +} + +fn main() { +} + diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index fa38482b21c50..48813ff142c18 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 c049fbc0fedbc..0e8e52df456af 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 c61f2ff79c019..c576c5e2edd64 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>, }