From d1cd689b4867e915e42264175d54c45f22180206 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 25 May 2015 15:06:38 +0200 Subject: [PATCH] rustdoc: Fix associated types in signatures Functions such as `fn foo(x: I::Item)` would not render correctly and displayed `I` instead of `I::Item`. Same thing with `I::Item` appearing in where bounds. This fixes the bug by using paths for generics. Fixes #24417 --- src/librustdoc/clean/mod.rs | 38 ++++++++++++++++++++++----------- src/librustdoc/html/format.rs | 6 +++--- src/test/rustdoc/assoc-types.rs | 22 +++++++++++++++++++ 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d985fa4c8cc6..701e99a6e3bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -664,6 +664,7 @@ impl Clean for ty::BuiltinBound { path: path, typarams: None, did: did, + is_generic: false, }, lifetimes: vec![] }, ast::TraitBoundModifier::None) @@ -706,7 +707,12 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { } TraitBound(PolyTrait { - trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, }, + trait_: ResolvedPath { + path: path, + typarams: None, + did: self.def_id, + is_generic: false, + }, lifetimes: late_bounds }, ast::TraitBoundModifier::None) } @@ -1394,11 +1400,13 @@ pub struct PolyTrait { /// it does not preserve mutability or boxes. #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub enum Type { - /// structs/enums/traits (anything that'd be an ast::TyPath) + /// structs/enums/traits (most that'd be an ast::TyPath) ResolvedPath { path: Path, typarams: Option>, did: ast::DefId, + /// true if is a `T::Name` path for associated types + is_generic: bool, }, /// For parameterized types, so the consumer of the JSON don't go /// looking for types which don't exist anywhere. @@ -1587,8 +1595,13 @@ impl Clean for ast::Ty { TyObjectSum(ref lhs, ref bounds) => { let lhs_ty = lhs.clean(cx); match lhs_ty { - ResolvedPath { path, typarams: None, did } => { - ResolvedPath { path: path, typarams: Some(bounds.clean(cx)), did: did} + ResolvedPath { path, typarams: None, did, is_generic } => { + ResolvedPath { + path: path, + typarams: Some(bounds.clean(cx)), + did: did, + is_generic: is_generic, + } } _ => { lhs_ty // shouldn't happen @@ -1668,6 +1681,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { path: path, typarams: None, did: did, + is_generic: false, } } ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { @@ -1682,6 +1696,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { path: path, typarams: Some(typarams), did: did, + is_generic: false, } } ty::ty_tup(ref t) => Tuple(t.clean(cx)), @@ -2572,10 +2587,7 @@ fn resolve_type(cx: &DocContext, None => panic!("unresolved id not in defmap") }; - match def { - def::DefSelfTy(..) if path.segments.len() == 1 => { - return Generic(token::get_name(special_idents::type_self.name).to_string()); - } + let is_generic = match def { def::DefPrimTy(p) => match p { ast::TyStr => return Primitive(Str), ast::TyBool => return Primitive(Bool), @@ -2593,13 +2605,14 @@ fn resolve_type(cx: &DocContext, ast::TyFloat(ast::TyF32) => return Primitive(F32), ast::TyFloat(ast::TyF64) => return Primitive(F64), }, - def::DefTyParam(_, _, _, n) => { - return Generic(token::get_name(n).to_string()) + def::DefSelfTy(..) if path.segments.len() == 1 => { + return Generic(token::get_name(special_idents::type_self.name).to_string()); } - _ => {} + def::DefSelfTy(..) | def::DefTyParam(..) => true, + _ => false, }; let did = register_def(&*cx, def); - ResolvedPath { path: path, typarams: None, did: did } + ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic } } fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId { @@ -2798,6 +2811,7 @@ fn lang_struct(cx: &DocContext, did: Option, } }], }, + is_generic: false, } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bb53d532f52f..e899f668e402 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -427,9 +427,9 @@ impl fmt::Display for clean::Type { clean::Generic(ref name) => { f.write_str(name) } - clean::ResolvedPath{ did, ref typarams, ref path } => { - // Paths like Self::Output should be rendered with all segments - try!(resolved_path(f, did, path, path.segments[0].name == "Self")); + clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => { + // Paths like T::Output and Self::Output should be rendered with all segments + try!(resolved_path(f, did, path, is_generic)); tybounds(f, typarams) } clean::Infer => write!(f, "_"), diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs index 20076a764943..d5047ade062d 100644 --- a/src/test/rustdoc/assoc-types.rs +++ b/src/test/rustdoc/assoc-types.rs @@ -18,3 +18,25 @@ pub trait Index { // "fn index<'a>(&'a self, index: I) -> &'a Self::Output" fn index<'a>(&'a self, index: I) -> &'a Self::Output; } + +// @has assoc_types/fn.use_output.html +// @has - '//*[@class="rust fn"]' '-> &T::Output' +pub fn use_output>(obj: &T, index: usize) -> &T::Output { + obj.index(index) +} + +pub trait Feed { + type Input; +} + +// @has assoc_types/fn.use_input.html +// @has - '//*[@class="rust fn"]' 'T::Input' +pub fn use_input(_feed: &T, _element: T::Input) { } + +// @has assoc_types/fn.cmp_input.html +// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq' +pub fn cmp_input(a: &T::Input, b: &U::Input) -> bool + where T::Input: PartialEq +{ + a == b +}