diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6dc6e80dae0..6808752b1fe 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -433,7 +433,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> {
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path.
fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
- print_all: bool) -> fmt::Result {
+ print_all: bool, use_absolute: bool) -> fmt::Result {
let last = path.segments.last().unwrap();
let rel_root = match &*path.segments[0].name {
"self" => Some("./".to_string()),
@@ -467,7 +467,17 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
if w.alternate() {
write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
} else {
- write!(w, "{}{}", HRef::new(did, &last.name), last.params)?;
+ let path = if use_absolute {
+ match href(did) {
+ Some((_, _, fqp)) => format!("{}::{}",
+ fqp[..fqp.len()-1].join("::"),
+ HRef::new(did, fqp.last().unwrap())),
+ None => format!("{}", HRef::new(did, &last.name)),
+ }
+ } else {
+ format!("{}", HRef::new(did, &last.name))
+ };
+ write!(w, "{}{}", path, last.params)?;
}
Ok(())
}
@@ -551,194 +561,198 @@ impl<'a> fmt::Display for HRef<'a> {
}
}
-impl fmt::Display for clean::Type {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- clean::Generic(ref name) => {
- f.write_str(name)
+fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, full_path: bool) -> fmt::Result {
+ match *t {
+ clean::Generic(ref name) => {
+ f.write_str(name)
+ }
+ clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
+ // Paths like T::Output and Self::Output should be rendered with all segments
+ resolved_path(f, did, path, is_generic, full_path)?;
+ tybounds(f, typarams)
+ }
+ clean::Infer => write!(f, "_"),
+ clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
+ clean::BareFunction(ref decl) => {
+ if f.alternate() {
+ write!(f, "{}{}fn{:#}{:#}",
+ UnsafetySpace(decl.unsafety),
+ AbiSpace(decl.abi),
+ decl.generics,
+ decl.decl)
+ } else {
+ write!(f, "{}{}fn{}{}",
+ UnsafetySpace(decl.unsafety),
+ AbiSpace(decl.abi),
+ decl.generics,
+ decl.decl)
}
- clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
- // Paths like T::Output and Self::Output should be rendered with all segments
- resolved_path(f, did, path, is_generic)?;
- tybounds(f, typarams)
- }
- clean::Infer => write!(f, "_"),
- clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
- clean::BareFunction(ref decl) => {
- if f.alternate() {
- write!(f, "{}{}fn{:#}{:#}",
- UnsafetySpace(decl.unsafety),
- AbiSpace(decl.abi),
- decl.generics,
- decl.decl)
- } else {
- write!(f, "{}{}fn{}{}",
- UnsafetySpace(decl.unsafety),
- AbiSpace(decl.abi),
- decl.generics,
- decl.decl)
+ }
+ clean::Tuple(ref typs) => {
+ match &typs[..] {
+ &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
+ &[ref one] => {
+ primitive_link(f, PrimitiveType::Tuple, "(")?;
+ //carry f.alternate() into this display w/o branching manually
+ fmt::Display::fmt(one, f)?;
+ primitive_link(f, PrimitiveType::Tuple, ",)")
+ }
+ many => {
+ primitive_link(f, PrimitiveType::Tuple, "(")?;
+ fmt::Display::fmt(&CommaSep(&many), f)?;
+ primitive_link(f, PrimitiveType::Tuple, ")")
}
}
- clean::Tuple(ref typs) => {
- match &typs[..] {
- &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
- &[ref one] => {
- primitive_link(f, PrimitiveType::Tuple, "(")?;
- //carry f.alternate() into this display w/o branching manually
- fmt::Display::fmt(one, f)?;
- primitive_link(f, PrimitiveType::Tuple, ",)")
- }
- many => {
- primitive_link(f, PrimitiveType::Tuple, "(")?;
- fmt::Display::fmt(&CommaSep(&many), f)?;
- primitive_link(f, PrimitiveType::Tuple, ")")
- }
- }
+ }
+ clean::Vector(ref t) => {
+ primitive_link(f, PrimitiveType::Slice, &format!("["))?;
+ fmt::Display::fmt(t, f)?;
+ primitive_link(f, PrimitiveType::Slice, &format!("]"))
+ }
+ clean::FixedVector(ref t, ref s) => {
+ primitive_link(f, PrimitiveType::Array, "[")?;
+ fmt::Display::fmt(t, f)?;
+ if f.alternate() {
+ primitive_link(f, PrimitiveType::Array,
+ &format!("; {}]", s))
+ } else {
+ primitive_link(f, PrimitiveType::Array,
+ &format!("; {}]", Escape(s)))
}
- clean::Vector(ref t) => {
- primitive_link(f, PrimitiveType::Slice, &format!("["))?;
- fmt::Display::fmt(t, f)?;
- primitive_link(f, PrimitiveType::Slice, &format!("]"))
- }
- clean::FixedVector(ref t, ref s) => {
- primitive_link(f, PrimitiveType::Array, "[")?;
- fmt::Display::fmt(t, f)?;
- if f.alternate() {
- primitive_link(f, PrimitiveType::Array,
- &format!("; {}]", s))
- } else {
- primitive_link(f, PrimitiveType::Array,
- &format!("; {}]", Escape(s)))
- }
- }
- clean::Never => f.write_str("!"),
- clean::RawPointer(m, ref t) => {
- match **t {
- clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
- if f.alternate() {
- primitive_link(f, clean::PrimitiveType::RawPointer,
- &format!("*{}{:#}", RawMutableSpace(m), t))
- } else {
- primitive_link(f, clean::PrimitiveType::RawPointer,
- &format!("*{}{}", RawMutableSpace(m), t))
- }
- }
- _ => {
+ }
+ clean::Never => f.write_str("!"),
+ clean::RawPointer(m, ref t) => {
+ match **t {
+ clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
+ if f.alternate() {
primitive_link(f, clean::PrimitiveType::RawPointer,
- &format!("*{}", RawMutableSpace(m)))?;
- fmt::Display::fmt(t, f)
+ &format!("*{}{:#}", RawMutableSpace(m), t))
+ } else {
+ primitive_link(f, clean::PrimitiveType::RawPointer,
+ &format!("*{}{}", RawMutableSpace(m), t))
}
}
+ _ => {
+ primitive_link(f, clean::PrimitiveType::RawPointer,
+ &format!("*{}", RawMutableSpace(m)))?;
+ fmt::Display::fmt(t, f)
+ }
}
- clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
- let lt = match *l {
- Some(ref l) => format!("{} ", *l),
- _ => "".to_string(),
- };
- let m = MutableSpace(mutability);
- match **ty {
- clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
- match **bt {
- clean::Generic(_) =>
- if f.alternate() {
- primitive_link(f, PrimitiveType::Slice,
- &format!("&{}{}[{:#}]", lt, m, **bt))
- } else {
- primitive_link(f, PrimitiveType::Slice,
- &format!("&{}{}[{}]", lt, m, **bt))
- },
- _ => {
- if f.alternate() {
- primitive_link(f, PrimitiveType::Slice,
- &format!("&{}{}[", lt, m))?;
- write!(f, "{:#}", **bt)?;
- } else {
- primitive_link(f, PrimitiveType::Slice,
- &format!("&{}{}[", lt, m))?;
- write!(f, "{}", **bt)?;
- }
- primitive_link(f, PrimitiveType::Slice, "]")
+ }
+ clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
+ let lt = match *l {
+ Some(ref l) => format!("{} ", *l),
+ _ => "".to_string(),
+ };
+ let m = MutableSpace(mutability);
+ match **ty {
+ clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
+ match **bt {
+ clean::Generic(_) =>
+ if f.alternate() {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[{:#}]", lt, m, **bt))
+ } else {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[{}]", lt, m, **bt))
+ },
+ _ => {
+ if f.alternate() {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[", lt, m))?;
+ write!(f, "{:#}", **bt)?;
+ } else {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[", lt, m))?;
+ write!(f, "{}", **bt)?;
}
- }
- }
- _ => {
- if f.alternate() {
- write!(f, "&{}{}{:#}", lt, m, **ty)
- } else {
- write!(f, "&{}{}{}", lt, m, **ty)
+ primitive_link(f, PrimitiveType::Slice, "]")
}
}
}
- }
- clean::PolyTraitRef(ref bounds) => {
- for (i, bound) in bounds.iter().enumerate() {
- if i != 0 {
- write!(f, " + ")?;
- }
+ _ => {
if f.alternate() {
- write!(f, "{:#}", *bound)?;
+ write!(f, "&{}{}{:#}", lt, m, **ty)
} else {
- write!(f, "{}", *bound)?;
+ write!(f, "&{}{}{}", lt, m, **ty)
}
}
- Ok(())
}
- clean::ImplTrait(ref bounds) => {
- write!(f, "impl ")?;
- for (i, bound) in bounds.iter().enumerate() {
- if i != 0 {
- write!(f, " + ")?;
- }
- if f.alternate() {
- write!(f, "{:#}", *bound)?;
- } else {
- write!(f, "{}", *bound)?;
- }
+ }
+ clean::PolyTraitRef(ref bounds) => {
+ for (i, bound) in bounds.iter().enumerate() {
+ if i != 0 {
+ write!(f, " + ")?;
}
- Ok(())
- }
- // It's pretty unsightly to look at `::C` in output, and
- // we've got hyperlinking on our side, so try to avoid longer
- // notation as much as possible by making `C` a hyperlink to trait
- // `B` to disambiguate.
- //
- // FIXME: this is still a lossy conversion and there should probably
- // be a better way of representing this in general? Most of
- // the ugliness comes from inlining across crates where
- // everything comes in as a fully resolved QPath (hard to
- // look at).
- clean::QPath {
- ref name,
- ref self_type,
- trait_: box clean::ResolvedPath { did, ref typarams, .. },
- } => {
if f.alternate() {
- write!(f, "{:#}::", self_type)?;
+ write!(f, "{:#}", *bound)?;
} else {
- write!(f, "{}::", self_type)?;
+ write!(f, "{}", *bound)?;
}
- let path = clean::Path::singleton(name.clone());
- resolved_path(f, did, &path, false)?;
+ }
+ Ok(())
+ }
+ clean::ImplTrait(ref bounds) => {
+ write!(f, "impl ")?;
+ for (i, bound) in bounds.iter().enumerate() {
+ if i != 0 {
+ write!(f, " + ")?;
+ }
+ if f.alternate() {
+ write!(f, "{:#}", *bound)?;
+ } else {
+ write!(f, "{}", *bound)?;
+ }
+ }
+ Ok(())
+ }
+ // It's pretty unsightly to look at `::C` in output, and
+ // we've got hyperlinking on our side, so try to avoid longer
+ // notation as much as possible by making `C` a hyperlink to trait
+ // `B` to disambiguate.
+ //
+ // FIXME: this is still a lossy conversion and there should probably
+ // be a better way of representing this in general? Most of
+ // the ugliness comes from inlining across crates where
+ // everything comes in as a fully resolved QPath (hard to
+ // look at).
+ clean::QPath {
+ ref name,
+ ref self_type,
+ trait_: box clean::ResolvedPath { did, ref typarams, .. },
+ } => {
+ if f.alternate() {
+ write!(f, "{:#}::", self_type)?;
+ } else {
+ write!(f, "{}::", self_type)?;
+ }
+ let path = clean::Path::singleton(name.clone());
+ resolved_path(f, did, &path, true, full_path)?;
- // FIXME: `typarams` are not rendered, and this seems bad?
- drop(typarams);
- Ok(())
- }
- clean::QPath { ref name, ref self_type, ref trait_ } => {
- if f.alternate() {
- write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
- } else {
- write!(f, "<{} as {}>::{}", self_type, trait_, name)
- }
- }
- clean::Unique(..) => {
- panic!("should have been cleaned")
+ // FIXME: `typarams` are not rendered, and this seems bad?
+ drop(typarams);
+ Ok(())
+ }
+ clean::QPath { ref name, ref self_type, ref trait_ } => {
+ if f.alternate() {
+ write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+ } else {
+ write!(f, "<{} as {}>::{}", self_type, trait_, name)
}
}
+ clean::Unique(..) => {
+ panic!("should have been cleaned")
+ }
}
}
-fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result {
+impl fmt::Display for clean::Type {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt_type(self, f, false)
+ }
+}
+
+fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool, full: bool) -> fmt::Result {
let mut plain = String::new();
if f.alternate() {
@@ -759,7 +773,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
plain.push_str(&format!("{:#}", ty));
} else {
match *ty {
- clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => {
+ clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
let last = path.segments.last().unwrap();
fmt::Display::fmt(&last.name, f)?;
fmt::Display::fmt(&last.params, f)?;
@@ -772,7 +786,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
plain.push_str(" for ");
}
- fmt::Display::fmt(&i.for_, f)?;
+ fmt_type(&i.for_, f, full)?;
plain.push_str(&format!("{:#}", i.for_));
fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;
@@ -781,13 +795,15 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
impl fmt::Display for clean::Impl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt_impl(self, f, true)
+ fmt_impl(self, f, true, false)
}
}
// The difference from above is that trait is not hyperlinked.
-pub fn fmt_impl_for_trait_page(i: &clean::Impl, f: &mut fmt::Formatter) -> fmt::Result {
- fmt_impl(i, f, false)
+pub fn fmt_impl_for_trait_page(i: &clean::Impl,
+ f: &mut fmt::Formatter,
+ disambiguate: bool) -> fmt::Result {
+ fmt_impl(i, f, false, disambiguate)
}
impl fmt::Display for clean::Arguments {
@@ -978,7 +994,7 @@ impl fmt::Display for clean::Import {
impl fmt::Display for clean::ImportSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.did {
- Some(did) => resolved_path(f, did, &self.path, true),
+ Some(did) => resolved_path(f, did, &self.path, true, false),
_ => {
for (i, seg) in self.path.segments.iter().enumerate() {
if i > 0 {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index e721b66779f..c7a25814553 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2111,9 +2111,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
")?;
if let Some(implementors) = cache.implementors.get(&it.def_id) {
- for i in implementors {
+ for k in implementors.iter() {
write!(w, "")?;
- fmt_impl_for_trait_page(&i.impl_, w)?;
+ // If there's already another implementor that has the same abbridged name, use the
+ // full path, for example in `std::iter::ExactSizeIterator`
+ let mut dissambiguate = false;
+ for l in implementors.iter() {
+ match (k.impl_.for_.clone(), l.impl_.for_.clone()) {
+ (clean::Type::ResolvedPath {path: path_a, ..},
+ clean::Type::ResolvedPath {path: path_b, ..}) => {
+ if k.def_id != l.def_id && path_a.last_name() == path_b.last_name() {
+ dissambiguate = true;
+ }
+ }
+ _ => (),
+ }
+ }
+ fmt_impl_for_trait_page(&k.impl_, w, dissambiguate)?;
writeln!(w, "
")?;
}
}