about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2020-12-22 20:22:47 -0500
committerJoshua Nelson <jyn514@gmail.com>2020-12-22 20:49:33 -0500
commit530c33cd5fd92c17e44c692bbe7a4006d57340f8 (patch)
tree540e442bd1d91e86124ff4b731423928c6ea865e
parent50a90975c0f78219db45d3bee0676a22695ec103 (diff)
downloadrust-530c33cd5fd92c17e44c692bbe7a4006d57340f8.tar.gz
rust-530c33cd5fd92c17e44c692bbe7a4006d57340f8.zip
Fix elided lifetimes shown as `'_` on async functions
-rw-r--r--src/librustdoc/clean/mod.rs25
-rw-r--r--src/test/rustdoc/async-fn.rs29
2 files changed, 52 insertions, 2 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 07255168d06..e7fdf76ba79 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -635,6 +635,18 @@ impl Clean<Generics> for hir::Generics<'_> {
                 _ => false,
             }
         }
+        /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
+        ///
+        /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
+        ///
+        /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
+        fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
+            match param.kind {
+                hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided } => true,
+                _ => false,
+            }
+        }
+
         let impl_trait_params = self
             .params
             .iter()
@@ -653,7 +665,7 @@ impl Clean<Generics> for hir::Generics<'_> {
             .collect::<Vec<_>>();
 
         let mut params = Vec::with_capacity(self.params.len());
-        for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
+        for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
             let p = p.clean(cx);
             params.push(p);
         }
@@ -1433,7 +1445,16 @@ impl Clean<Type> for hir::Ty<'_> {
             TyKind::Never => Never,
             TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)),
             TyKind::Rptr(ref l, ref m) => {
-                let lifetime = if l.is_elided() { None } else { Some(l.clean(cx)) };
+                // There are two times a `Fresh` lifetime can be created:
+                // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
+                // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
+                //    See commit 749349fc9f7b12f212bca9ba2297e463328cb701 for more information.
+                // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
+                // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
+                // there's no case where it could cause the function to fail to compile.
+                let elided =
+                    l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
+                let lifetime = if elided { None } else { Some(l.clean(cx)) };
                 BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
             }
             TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs
index e7a7d1831f7..7a673b9f670 100644
--- a/src/test/rustdoc/async-fn.rs
+++ b/src/test/rustdoc/async-fn.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-linelength
 // edition:2018
 #![feature(min_const_generics)]
 
@@ -52,3 +53,31 @@ pub trait Trait<const N: usize> {}
 // @has async_fn/fn.const_generics.html
 // @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
 pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
+
+// test that elided lifetimes are properly elided and not displayed as `'_`
+// regression test for #63037
+// @has async_fn/fn.elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
+pub async fn elided(foo: &str) -> &str {}
+// This should really be shown as written, but for implementation reasons it's difficult.
+// See `impl Clean for TyKind::Rptr`.
+// @has async_fn/fn.user_elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
+pub async fn user_elided(foo: &'_ str) -> &str {}
+// @has async_fn/fn.static_trait.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
+pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
+// @has async_fn/fn.lifetime_for_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
+pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
+
+struct AsyncFdReadyGuard<'a, T> { x: &'a T }
+
+impl Foo {
+    // @has async_fn/struct.Foo.html
+    // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
+    // taken from `tokio` as an example of a method that was particularly bad before
+    // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
+}