Skip to content

Commit

Permalink
rustdoc: Fix associated types in signatures
Browse files Browse the repository at this point in the history
Functions such as `fn foo<I: Iterator>(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
  • Loading branch information
Ulrik Sverdrup committed May 25, 2015
1 parent 093e18d commit d1cd689
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 15 deletions.
38 changes: 26 additions & 12 deletions src/librustdoc/clean/mod.rs
Expand Up @@ -664,6 +664,7 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
path: path,
typarams: None,
did: did,
is_generic: false,
},
lifetimes: vec![]
}, ast::TraitBoundModifier::None)
Expand Down Expand Up @@ -706,7 +707,12 @@ impl<'tcx> Clean<TyParamBound> 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)
}
Expand Down Expand Up @@ -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<Vec<TyParamBound>>,
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.
Expand Down Expand Up @@ -1587,8 +1595,13 @@ impl Clean<Type> 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
Expand Down Expand Up @@ -1668,6 +1681,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
path: path,
typarams: None,
did: did,
is_generic: false,
}
}
ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
Expand All @@ -1682,6 +1696,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
path: path,
typarams: Some(typarams),
did: did,
is_generic: false,
}
}
ty::ty_tup(ref t) => Tuple(t.clean(cx)),
Expand Down Expand Up @@ -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),
Expand All @@ -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 {
Expand Down Expand Up @@ -2798,6 +2811,7 @@ fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
}
}],
},
is_generic: false,
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/html/format.rs
Expand Up @@ -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, "_"),
Expand Down
22 changes: 22 additions & 0 deletions src/test/rustdoc/assoc-types.rs
Expand Up @@ -18,3 +18,25 @@ pub trait Index<I: ?Sized> {
// "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<T: Index<usize>>(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<T: Feed>(_feed: &T, _element: T::Input) { }

// @has assoc_types/fn.cmp_input.html
// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>'
pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool
where T::Input: PartialEq<U::Input>
{
a == b
}

0 comments on commit d1cd689

Please sign in to comment.