Skip to content

Commit 5aa9602

Browse files
authored
Rollup merge of #41249 - GuillaumeGomez:rustdoc-render, r=steveklabnik,frewsxcv
Fix invalid associated type rendering in rustdoc Fixes #41036. r? @rust-lang/docs
2 parents 5d7467a + dd7dfe5 commit 5aa9602

File tree

3 files changed

+101
-42
lines changed

3 files changed

+101
-42
lines changed

src/librustdoc/clean/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2285,7 +2285,7 @@ impl Clean<PathParameters> for hir::PathParameters {
22852285
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
22862286
pub struct PathSegment {
22872287
pub name: String,
2288-
pub params: PathParameters
2288+
pub params: PathParameters,
22892289
}
22902290

22912291
impl Clean<PathSegment> for hir::PathSegment {

src/librustdoc/html/format.rs

+74-41
Original file line numberDiff line numberDiff line change
@@ -470,10 +470,22 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
470470
/// rendering function with the necessary arguments for linking to a local path.
471471
fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
472472
print_all: bool, use_absolute: bool, is_not_debug: bool) -> fmt::Result {
473-
let last = path.segments.last().unwrap();
474-
let rel_root = match &*path.segments[0].name {
475-
"self" => Some("./".to_string()),
476-
_ => None,
473+
let empty = clean::PathSegment {
474+
name: String::new(),
475+
params: clean::PathParameters::Parenthesized {
476+
inputs: Vec::new(),
477+
output: None,
478+
}
479+
};
480+
let last = path.segments.last()
481+
.unwrap_or(&empty);
482+
let rel_root = if path.segments.is_empty() {
483+
None
484+
} else {
485+
match &*path.segments[0].name {
486+
"self" => Some("./".to_string()),
487+
_ => None,
488+
}
477489
};
478490

479491
if print_all {
@@ -487,10 +499,9 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
487499
root.push_str(&seg.name);
488500
root.push_str("/");
489501
if is_not_debug {
490-
write!(w, "<a class=\"mod\"
491-
href=\"{}index.html\">{}</a>::",
492-
root,
493-
seg.name)?;
502+
write!(w, "<a class=\"mod\" href=\"{}index.html\">{}</a>::",
503+
root,
504+
seg.name)?;
494505
} else {
495506
write!(w, "{}::", seg.name)?;
496507
}
@@ -516,7 +527,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
516527
match href(did) {
517528
Some((_, _, fqp)) => format!("{}::{}",
518529
fqp[..fqp.len()-1].join("::"),
519-
HRef::new(did, fqp.last().unwrap())),
530+
HRef::new(did, fqp.last()
531+
.unwrap_or(&String::new()))),
520532
None => format!("{}", HRef::new(did, &last.name)),
521533
}
522534
} else {
@@ -528,7 +540,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
528540
match href(did) {
529541
Some((_, _, fqp)) => format!("{:?}::{:?}",
530542
fqp[..fqp.len()-1].join("::"),
531-
HRef::new(did, fqp.last().unwrap())),
543+
HRef::new(did, fqp.last()
544+
.unwrap_or(&String::new()))),
532545
None => format!("{:?}", HRef::new(did, &last.name)),
533546
}
534547
} else {
@@ -801,45 +814,65 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
801814
}
802815
Ok(())
803816
}
804-
// It's pretty unsightly to look at `<A as B>::C` in output, and
805-
// we've got hyperlinking on our side, so try to avoid longer
806-
// notation as much as possible by making `C` a hyperlink to trait
807-
// `B` to disambiguate.
808-
//
809-
// FIXME: this is still a lossy conversion and there should probably
810-
// be a better way of representing this in general? Most of
811-
// the ugliness comes from inlining across crates where
812-
// everything comes in as a fully resolved QPath (hard to
813-
// look at).
814-
clean::QPath {
815-
ref name,
816-
ref self_type,
817-
trait_: box clean::ResolvedPath { did, ref typarams, .. },
818-
} => {
819-
if f.alternate() {
820-
write!(f, "{:#}::", self_type)?;
821-
} else {
822-
write!(f, "{}::", self_type)?;
823-
}
824-
let path = clean::Path::singleton(name.clone());
825-
resolved_path(f, did, &path, true, use_absolute, is_not_debug)?;
826-
827-
// FIXME: `typarams` are not rendered, and this seems bad?
828-
drop(typarams);
829-
Ok(())
830-
}
831817
clean::QPath { ref name, ref self_type, ref trait_ } => {
818+
let should_show_cast = match *trait_ {
819+
box clean::ResolvedPath { .. } => {
820+
let path = clean::Path::singleton(name.clone());
821+
!path.segments.is_empty() && &format!("{:#}", trait_) != "()" &&
822+
&format!("{:#}", self_type) != "Self"
823+
}
824+
_ => true,
825+
};
832826
if f.alternate() {
833827
if is_not_debug {
834-
write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
828+
if should_show_cast {
829+
write!(f, "<{:#} as {:#}>::", self_type, trait_)?
830+
} else {
831+
write!(f, "{:#}::", self_type)?
832+
}
835833
} else {
836-
write!(f, "<{:#?} as {:#?}>::{}", self_type, trait_, name)
834+
if should_show_cast {
835+
write!(f, "<{:#?} as {:#?}>::", self_type, trait_)?
836+
} else {
837+
write!(f, "{:#?}::", self_type)?
838+
}
837839
}
838840
} else {
839841
if is_not_debug {
840-
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
842+
if should_show_cast {
843+
write!(f, "&lt;{} as {}&gt;::", self_type, trait_)?
844+
} else {
845+
write!(f, "{}::", self_type)?
846+
}
841847
} else {
842-
write!(f, "<{:?} as {:?}>::{}", self_type, trait_, name)
848+
if should_show_cast {
849+
write!(f, "<{:?} as {:?}>::", self_type, trait_)?
850+
} else {
851+
write!(f, "{:?}::", self_type)?
852+
}
853+
}
854+
};
855+
match *trait_ {
856+
// It's pretty unsightly to look at `<A as B>::C` in output, and
857+
// we've got hyperlinking on our side, so try to avoid longer
858+
// notation as much as possible by making `C` a hyperlink to trait
859+
// `B` to disambiguate.
860+
//
861+
// FIXME: this is still a lossy conversion and there should probably
862+
// be a better way of representing this in general? Most of
863+
// the ugliness comes from inlining across crates where
864+
// everything comes in as a fully resolved QPath (hard to
865+
// look at).
866+
box clean::ResolvedPath { did, ref typarams, .. } => {
867+
let path = clean::Path::singleton(name.clone());
868+
resolved_path(f, did, &path, true, use_absolute, is_not_debug)?;
869+
870+
// FIXME: `typarams` are not rendered, and this seems bad?
871+
drop(typarams);
872+
Ok(())
873+
}
874+
_ => {
875+
write!(f, "{}", name)
843876
}
844877
}
845878
}

src/test/rustdoc/assoc-item-cast.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_name = "foo"]
12+
13+
// ignore-tidy-linelength
14+
15+
pub trait Expression {
16+
type SqlType;
17+
}
18+
19+
pub trait AsExpression<T> {
20+
type Expression: Expression<SqlType = T>;
21+
fn as_expression(self) -> Self::Expression;
22+
}
23+
24+
// @has foo/type.AsExprOf.html
25+
// @has - '//*[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
26+
pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;

0 commit comments

Comments
 (0)