Skip to content

Commit 1f65f56

Browse files
committed
rustdoc: Render for<'_> lifetimes in trait objects
1 parent e0162a8 commit 1f65f56

File tree

6 files changed

+61
-29
lines changed

6 files changed

+61
-29
lines changed

src/librustdoc/clean/mod.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -1378,8 +1378,9 @@ impl Clean<Type> for hir::Ty<'_> {
13781378
}
13791379
TyKind::Path(_) => clean_qpath(&self, cx),
13801380
TyKind::TraitObject(ref bounds, ref lifetime, _) => {
1381-
match bounds[0].clean(cx).trait_ {
1382-
ResolvedPath { path, param_names: None, did, is_generic } => {
1381+
let cleaned = bounds[0].clean(cx);
1382+
match cleaned.trait_ {
1383+
ResolvedPath { path, param_names: None, did, is_generic, .. } => {
13831384
let mut bounds: Vec<self::GenericBound> = bounds[1..]
13841385
.iter()
13851386
.map(|bound| {
@@ -1392,7 +1393,12 @@ impl Clean<Type> for hir::Ty<'_> {
13921393
if !lifetime.is_elided() {
13931394
bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
13941395
}
1395-
ResolvedPath { path, param_names: Some(bounds), did, is_generic }
1396+
ResolvedPath {
1397+
path,
1398+
param_names: Some((bounds, cleaned.generic_params)),
1399+
did,
1400+
is_generic,
1401+
}
13961402
}
13971403
_ => Infer, // shouldn't happen
13981404
}
@@ -1542,7 +1548,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
15421548

15431549
let path =
15441550
external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
1545-
ResolvedPath { path, param_names: Some(param_names), did, is_generic: false }
1551+
ResolvedPath {
1552+
path,
1553+
param_names: Some((param_names, vec![])),
1554+
did,
1555+
is_generic: false,
1556+
}
15461557
}
15471558
ty::Tuple(ref t) => {
15481559
Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
@@ -2248,7 +2259,7 @@ impl From<GenericBound> for SimpleBound {
22482259
GenericBound::TraitBound(t, mod_) => match t.trait_ {
22492260
Type::ResolvedPath { path, param_names, .. } => SimpleBound::TraitBound(
22502261
path.segments,
2251-
param_names.map_or_else(Vec::new, |v| {
2262+
param_names.map_or_else(Vec::new, |(v, _)| {
22522263
v.iter().map(|p| SimpleBound::from(p.clone())).collect()
22532264
}),
22542265
t.generic_params,

src/librustdoc/clean/types.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,9 @@ crate enum Type {
14071407
/// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
14081408
ResolvedPath {
14091409
path: Path,
1410-
param_names: Option<Vec<GenericBound>>,
1410+
/// If `param_names` is `Some`, this path is a trait object and the Vecs repsresent
1411+
/// `(generic bounds, generic parameters)`
1412+
param_names: Option<(Vec<GenericBound>, Vec<GenericParamDef>)>,
14111413
did: DefId,
14121414
/// `true` if is a `T::Name` path for associated types.
14131415
is_generic: bool,

src/librustdoc/html/format.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -646,11 +646,11 @@ fn primitive_link(
646646

647647
/// Helper to render type parameters
648648
fn tybounds<'a, 'tcx: 'a>(
649-
param_names: &'a Option<Vec<clean::GenericBound>>,
649+
param_names: Option<&'a Vec<clean::GenericBound>>,
650650
cx: &'a Context<'tcx>,
651651
) -> impl fmt::Display + 'a + Captures<'tcx> {
652-
display_fn(move |f| match *param_names {
653-
Some(ref params) => {
652+
display_fn(move |f| match param_names {
653+
Some(params) => {
654654
for param in params {
655655
write!(f, " + ")?;
656656
fmt::Display::fmt(&param.print(cx), f)?;
@@ -695,8 +695,27 @@ fn fmt_type<'cx>(
695695
match *t {
696696
clean::Generic(name) => write!(f, "{}", name),
697697
clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
698-
if param_names.is_some() {
698+
let generic_params = param_names.as_ref().map(|(_, x)| x);
699+
let param_names = param_names.as_ref().map(|(x, _)| x);
700+
701+
if let Some(generic_params) = generic_params {
699702
f.write_str("dyn ")?;
703+
704+
if !generic_params.is_empty() {
705+
if f.alternate() {
706+
write!(
707+
f,
708+
"for<{:#}> ",
709+
comma_sep(generic_params.iter().map(|g| g.print(cx)))
710+
)?;
711+
} else {
712+
write!(
713+
f,
714+
"for&lt;{}&gt; ",
715+
comma_sep(generic_params.iter().map(|g| g.print(cx)))
716+
)?;
717+
}
718+
}
700719
}
701720
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
702721
resolved_path(f, did, path, is_generic, use_absolute, cx)?;
@@ -835,7 +854,7 @@ fn fmt_type<'cx>(
835854
}
836855
}
837856
}
838-
clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => {
857+
clean::ResolvedPath { param_names: Some((ref v, _)), .. } if !v.is_empty() => {
839858
write!(f, "{}{}{}(", amp, lt, m)?;
840859
fmt_type(&ty, f, use_absolute, cx)?;
841860
write!(f, ")")

src/librustdoc/json/conversions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ impl FromWithTcx<clean::Type> for Type {
378378
id: from_def_id(did.into()),
379379
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
380380
param_names: param_names
381-
.map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
381+
.map(|(v, _)| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
382382
.unwrap_or_default(),
383383
},
384384
Generic(s) => Type::Generic(s.to_string()),

src/test/rustdoc/for-lifetime.rs

-12
This file was deleted.

src/test/rustdoc/higher-ranked-trait-bounds.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![crate_name = "foo"]
22

3-
trait A<'x> {}
3+
// @has foo/trait.Trait.html
4+
pub trait Trait<'x> {}
45

56
// @has foo/fn.test1.html
67
// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
@@ -11,10 +12,10 @@ where
1112
}
1213

1314
// @has foo/fn.test2.html
14-
// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: A<'b>,"
15+
// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: Trait<'b>,"
1516
pub fn test2<T>()
1617
where
17-
for<'a, 'b> &'a T: A<'b>,
18+
for<'a, 'b> &'a T: Trait<'b>,
1819
{
1920
}
2021

@@ -29,13 +30,24 @@ where
2930
// @has foo/struct.Foo.html
3031
pub struct Foo<'a> {
3132
_x: &'a u8,
33+
pub some_trait: &'a dyn for<'b> Trait<'b>,
34+
pub some_func: for<'c> fn(val: &'c i32) -> i32,
3235
}
3336

37+
// @has - '//span[@id="structfield.some_func"]' "some_func: for<'c> fn(val: &'c i32) -> i32"
38+
// @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>"
39+
3440
impl<'a> Foo<'a> {
35-
// @has - '//code' "pub fn bar<T>() where T: A<'a>,"
41+
// @has - '//code' "pub fn bar<T>() where T: Trait<'a>,"
3642
pub fn bar<T>()
3743
where
38-
T: A<'a>,
44+
T: Trait<'a>,
3945
{
4046
}
4147
}
48+
49+
// @has foo/trait.B.html
50+
pub trait B<'x> {}
51+
52+
// @has - '//code[@class="in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
53+
impl<'a> B<'a> for dyn for<'b> Trait<'b> {}

0 commit comments

Comments
 (0)