about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJustus K <justus.k@protonmail.com>2021-05-18 10:06:24 +0200
committerJustus K <justus.k@protonmail.com>2021-06-18 21:58:09 +0200
commit1f65f56461fa72df809fff43975a7e72f08fda44 (patch)
tree3467d490de695f02614249f972a3eba12651738a
parente0162a8a56d1c59e185e293f33c38d94a5a2d462 (diff)
downloadrust-1f65f56461fa72df809fff43975a7e72f08fda44.tar.gz
rust-1f65f56461fa72df809fff43975a7e72f08fda44.zip
rustdoc: Render `for<'_>` lifetimes in trait objects
-rw-r--r--src/librustdoc/clean/mod.rs21
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/html/format.rs29
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/test/rustdoc/for-lifetime.rs12
-rw-r--r--src/test/rustdoc/higher-ranked-trait-bounds.rs22
6 files changed, 61 insertions, 29 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 634a8dae763..889e645309c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1378,8 +1378,9 @@ impl Clean<Type> for hir::Ty<'_> {
             }
             TyKind::Path(_) => clean_qpath(&self, cx),
             TyKind::TraitObject(ref bounds, ref lifetime, _) => {
-                match bounds[0].clean(cx).trait_ {
-                    ResolvedPath { path, param_names: None, did, is_generic } => {
+                let cleaned = bounds[0].clean(cx);
+                match cleaned.trait_ {
+                    ResolvedPath { path, param_names: None, did, is_generic, .. } => {
                         let mut bounds: Vec<self::GenericBound> = bounds[1..]
                             .iter()
                             .map(|bound| {
@@ -1392,7 +1393,12 @@ impl Clean<Type> for hir::Ty<'_> {
                         if !lifetime.is_elided() {
                             bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
                         }
-                        ResolvedPath { path, param_names: Some(bounds), did, is_generic }
+                        ResolvedPath {
+                            path,
+                            param_names: Some((bounds, cleaned.generic_params)),
+                            did,
+                            is_generic,
+                        }
                     }
                     _ => Infer, // shouldn't happen
                 }
@@ -1542,7 +1548,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
                 let path =
                     external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
-                ResolvedPath { path, param_names: Some(param_names), did, is_generic: false }
+                ResolvedPath {
+                    path,
+                    param_names: Some((param_names, vec![])),
+                    did,
+                    is_generic: false,
+                }
             }
             ty::Tuple(ref t) => {
                 Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
@@ -2248,7 +2259,7 @@ impl From<GenericBound> for SimpleBound {
             GenericBound::TraitBound(t, mod_) => match t.trait_ {
                 Type::ResolvedPath { path, param_names, .. } => SimpleBound::TraitBound(
                     path.segments,
-                    param_names.map_or_else(Vec::new, |v| {
+                    param_names.map_or_else(Vec::new, |(v, _)| {
                         v.iter().map(|p| SimpleBound::from(p.clone())).collect()
                     }),
                     t.generic_params,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5d036d4d35b..4c94501b80b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1407,7 +1407,9 @@ crate enum Type {
     /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
     ResolvedPath {
         path: Path,
-        param_names: Option<Vec<GenericBound>>,
+        /// If `param_names` is `Some`, this path is a trait object and the Vecs repsresent
+        /// `(generic bounds, generic parameters)`
+        param_names: Option<(Vec<GenericBound>, Vec<GenericParamDef>)>,
         did: DefId,
         /// `true` if is a `T::Name` path for associated types.
         is_generic: bool,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index a424932d83f..e4fb7384aff 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -646,11 +646,11 @@ fn primitive_link(
 
 /// Helper to render type parameters
 fn tybounds<'a, 'tcx: 'a>(
-    param_names: &'a Option<Vec<clean::GenericBound>>,
+    param_names: Option<&'a Vec<clean::GenericBound>>,
     cx: &'a Context<'tcx>,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
-    display_fn(move |f| match *param_names {
-        Some(ref params) => {
+    display_fn(move |f| match param_names {
+        Some(params) => {
             for param in params {
                 write!(f, " + ")?;
                 fmt::Display::fmt(&param.print(cx), f)?;
@@ -695,8 +695,27 @@ fn fmt_type<'cx>(
     match *t {
         clean::Generic(name) => write!(f, "{}", name),
         clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
-            if param_names.is_some() {
+            let generic_params = param_names.as_ref().map(|(_, x)| x);
+            let param_names = param_names.as_ref().map(|(x, _)| x);
+
+            if let Some(generic_params) = generic_params {
                 f.write_str("dyn ")?;
+
+                if !generic_params.is_empty() {
+                    if f.alternate() {
+                        write!(
+                            f,
+                            "for<{:#}> ",
+                            comma_sep(generic_params.iter().map(|g| g.print(cx)))
+                        )?;
+                    } else {
+                        write!(
+                            f,
+                            "for&lt;{}&gt; ",
+                            comma_sep(generic_params.iter().map(|g| g.print(cx)))
+                        )?;
+                    }
+                }
             }
             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
             resolved_path(f, did, path, is_generic, use_absolute, cx)?;
@@ -835,7 +854,7 @@ fn fmt_type<'cx>(
                         }
                     }
                 }
-                clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => {
+                clean::ResolvedPath { param_names: Some((ref v, _)), .. } if !v.is_empty() => {
                     write!(f, "{}{}{}(", amp, lt, m)?;
                     fmt_type(&ty, f, use_absolute, cx)?;
                     write!(f, ")")
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index c844d91096a..643c0f82ae9 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -378,7 +378,7 @@ impl FromWithTcx<clean::Type> for Type {
                 id: from_def_id(did.into()),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: param_names
-                    .map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
+                    .map(|(v, _)| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
                     .unwrap_or_default(),
             },
             Generic(s) => Type::Generic(s.to_string()),
diff --git a/src/test/rustdoc/for-lifetime.rs b/src/test/rustdoc/for-lifetime.rs
deleted file mode 100644
index 34a7eae31c7..00000000000
--- a/src/test/rustdoc/for-lifetime.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![crate_name = "foo"]
-#![crate_type = "lib"]
-
-pub struct Foo {
-    pub some_func: for<'a> fn(val: &'a i32) -> i32,
-    pub some_trait: dyn for<'a> Trait<'a>,
-}
-
-// @has foo/struct.Foo.html '//span[@id="structfield.some_func"]' "some_func: for<'a> fn(val: &'a i32) -> i32"
-// @has foo/struct.Foo.html '//span[@id="structfield.some_trait"]' "some_trait: dyn Trait<'a>"
-
-pub trait Trait<'a> {}
diff --git a/src/test/rustdoc/higher-ranked-trait-bounds.rs b/src/test/rustdoc/higher-ranked-trait-bounds.rs
index b5c55df287b..492a743fbf2 100644
--- a/src/test/rustdoc/higher-ranked-trait-bounds.rs
+++ b/src/test/rustdoc/higher-ranked-trait-bounds.rs
@@ -1,6 +1,7 @@
 #![crate_name = "foo"]
 
-trait A<'x> {}
+// @has foo/trait.Trait.html
+pub trait Trait<'x> {}
 
 // @has foo/fn.test1.html
 // @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
@@ -11,10 +12,10 @@ where
 }
 
 // @has foo/fn.test2.html
-// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: A<'b>,"
+// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: Trait<'b>,"
 pub fn test2<T>()
 where
-    for<'a, 'b> &'a T: A<'b>,
+    for<'a, 'b> &'a T: Trait<'b>,
 {
 }
 
@@ -29,13 +30,24 @@ where
 // @has foo/struct.Foo.html
 pub struct Foo<'a> {
     _x: &'a u8,
+    pub some_trait: &'a dyn for<'b> Trait<'b>,
+    pub some_func: for<'c> fn(val: &'c i32) -> i32,
 }
 
+// @has - '//span[@id="structfield.some_func"]' "some_func: for<'c> fn(val: &'c i32) -> i32"
+// @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>"
+
 impl<'a> Foo<'a> {
-    // @has - '//code' "pub fn bar<T>() where T: A<'a>,"
+    // @has - '//code' "pub fn bar<T>() where T: Trait<'a>,"
     pub fn bar<T>()
     where
-        T: A<'a>,
+        T: Trait<'a>,
     {
     }
 }
+
+// @has foo/trait.B.html
+pub trait B<'x> {}
+
+// @has - '//code[@class="in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
+impl<'a> B<'a> for dyn for<'b> Trait<'b> {}