Auto merge of #25675 - bluss:rustdoc-assoc-types-index, r=alexcrichton

rustdoc: Associated type fixes

The first commit fixes a bug with "dud" items in the search index from
misrepresented `type` items in trait impl blocks.

For a trait *implementation* there are typedefs which are the types for
that particular trait and implementor. Skip these in the search index.

There were lots of dud items in the search index due to this (search for
Item, Iterator's associated type).

Add a boolean to clean::TypedefItem so that it tracks whether the it is
a type alias on its own, or if it's a `type` item in a trait impl.

The second commit fixes a bug that made signatures and where bounds
using associated types (if they were not on `Self`) incorrect.

The third commit fixes so that where clauses in type alias definititons
are shown.

Fixes #22442
Fixes #24417
Fixes #25769
This commit is contained in:
bors 2015-05-26 21:36:57 +00:00
commit cccc137b88
7 changed files with 83 additions and 28 deletions

View File

@ -217,7 +217,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn
clean::TypedefItem(clean::Typedef {
type_: t.ty.clean(cx),
generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
})
}, false)
}
pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
@ -370,7 +370,7 @@ pub fn build_impl(cx: &DocContext,
subst::ParamSpace::TypeSpace).clean(cx);
Some(clean::Item {
name: Some(assoc_ty.name.clean(cx)),
inner: clean::TypedefItem(typedef),
inner: clean::TypedefItem(typedef, true),
source: clean::Span::empty(),
attrs: vec![],
visibility: None,

View File

@ -343,7 +343,7 @@ pub enum ItemEnum {
EnumItem(Enum),
FunctionItem(Function),
ModuleItem(Module),
TypedefItem(Typedef),
TypedefItem(Typedef, bool /* is associated type */),
StaticItem(Static),
ConstantItem(Constant),
TraitItem(Trait),
@ -664,6 +664,7 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
path: path,
typarams: None,
did: did,
is_generic: false,
},
lifetimes: vec![]
}, ast::TraitBoundModifier::None)
@ -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)
}
@ -1286,7 +1292,7 @@ impl Clean<Item> for ast::ImplItem {
type_params: Vec::new(),
where_predicates: Vec::new()
},
}),
}, true),
ast::MacImplItem(_) => {
MacroItem(Macro {
source: self.span.to_src(cx),
@ -1401,11 +1407,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.
@ -1594,8 +1602,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
@ -1675,6 +1688,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 }) => {
@ -1689,6 +1703,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)),
@ -2085,7 +2100,7 @@ impl Clean<Item> for doctree::Typedef {
inner: TypedefItem(Typedef {
type_: self.ty.clean(cx),
generics: self.gen.clean(cx),
}),
}, false),
}
}
}
@ -2255,7 +2270,7 @@ fn build_deref_target_impls(cx: &DocContext,
for item in items {
let target = match item.inner {
TypedefItem(ref t) => &t.type_,
TypedefItem(ref t, true) => &t.type_,
_ => continue,
};
let primitive = match *target {
@ -2580,10 +2595,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),
@ -2601,13 +2613,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 {
@ -2821,6 +2834,7 @@ fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
}
}],
},
is_generic: false,
}
}

View File

@ -437,9 +437,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, "_"),

View File

@ -865,7 +865,7 @@ impl DocFolder for Cache {
clean::StructItem(ref s) => self.generics(&s.generics),
clean::EnumItem(ref e) => self.generics(&e.generics),
clean::FunctionItem(ref f) => self.generics(&f.generics),
clean::TypedefItem(ref t) => self.generics(&t.generics),
clean::TypedefItem(ref t, _) => self.generics(&t.generics),
clean::TraitItem(ref t) => self.generics(&t.generics),
clean::ImplItem(ref i) => self.generics(&i.generics),
clean::TyMethodItem(ref i) => self.generics(&i.generics),
@ -931,6 +931,10 @@ impl DocFolder for Cache {
((Some(*last), path), true)
}
}
clean::TypedefItem(_, true) => {
// skip associated types in impls
((None, None), false)
}
_ => ((None, Some(&*self.stack)), false)
};
let hidden_field = match item.inner {
@ -1492,7 +1496,7 @@ impl<'a> fmt::Display for Item<'a> {
clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
clean::StructItem(ref s) => item_struct(fmt, self.item, s),
clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
clean::TypedefItem(ref t, _) => item_typedef(fmt, self.item, t),
clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p),
clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
@ -2304,10 +2308,10 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
let deref_type = impl_.impl_.trait_.as_ref().unwrap();
let target = impl_.impl_.items.iter().filter_map(|item| {
match item.inner {
clean::TypedefItem(ref t) => Some(&t.type_),
clean::TypedefItem(ref t, true) => Some(&t.type_),
_ => None,
}
}).next().unwrap();
}).next().expect("Expected associated type binding");
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
match *target {
clean::ResolvedPath { did, .. } => render_assoc_items(w, did, what),
@ -2357,7 +2361,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
try!(write!(w, "</code></h4>\n"));
}
}
clean::TypedefItem(ref tydef) => {
clean::TypedefItem(ref tydef, _) => {
let name = item.name.as_ref().unwrap();
try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>",
*name,
@ -2447,10 +2451,11 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
t: &clean::Typedef) -> fmt::Result {
try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
try!(write!(w, "<pre class='rust typedef'>type {}{}{where_clause} = {type_};</pre>",
it.name.as_ref().unwrap(),
t.generics,
t.type_));
where_clause = WhereClause(&t.generics),
type_ = t.type_));
document(w, it)
}

View File

@ -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
}

View File

@ -10,6 +10,8 @@
#![crate_name = "rustdoc_test"]
use std::ops::Deref;
// @has search-index.js Foo
pub use private::Foo;
@ -24,3 +26,11 @@ mod private {
fn trait_method(&self) {} // @!has - priv_method
}
}
pub struct Bar;
impl Deref for Bar {
// @!has search-index.js Target
type Target = Bar;
fn deref(&self) -> &Bar { self }
}

View File

@ -42,3 +42,7 @@ pub enum Foxtrot<F> { Foxtrot1(F) }
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
// "type Golf<T> where T: Clone = (T, T)"
pub type Golf<T> where T: Clone = (T, T);