diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c322b4aae7e..bf937439981 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -118,10 +118,11 @@ impl Substs { pub fn new_trait(t: Vec, r: Vec, + a: Vec, s: ty::t) -> Substs { - Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new(), Vec::new()), + Substs::new(VecPerParamSpace::new(t, vec!(s), a, Vec::new()), VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new())) } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index a665e1f0a26..abc36359a85 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1683,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/ty.rs b/src/librustc/middle/ty.rs index b9af31665a1..8211fec505b 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 66d4f73eacc..951ac795d80 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 66c311e4d66..863f09736ab 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -305,6 +305,12 @@ fn collect_trait_methods(ccx: &CrateCtxt, } }); + 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 @@ -460,7 +466,7 @@ 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.ty_param.id) @@ -475,7 +481,7 @@ fn convert_associated_type(ccx: &CrateCtxt, } }; let param_type = ty::mk_param(ccx.tcx, - subst::TypeSpace, + type_parameter_def.space, type_parameter_def.index, local_def(associated_type.ty_param.id)); ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.ty_param.id), @@ -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(_) => {} @@ -980,7 +979,7 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { ast::TypeTraitItem(ref item) => { 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.ty_param.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) } } @@ -1680,14 +1683,14 @@ fn ty_generics_for_trait(ccx: &CrateCtxt, let def = get_or_create_type_parameter_def( ccx, - subst::TypeSpace, + 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(_) => {} } @@ -1786,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.ty_param.id), - index: index, - name: associated_type.ty_param.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() { @@ -1886,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); } } @@ -1976,6 +1859,83 @@ fn ty_generics<'tcx,AC>(this: &AC, } return result; + + 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; + } + } + } + } } fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 227a9b1bdcc..55c3c236853 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 1d769572ffe..c4f98858030 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 { @@ -725,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)) } @@ -740,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)) @@ -758,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)) @@ -1261,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/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs new file mode 100644 index 00000000000..47ab09d279f --- /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() { +} +