Skip to content

Commit 530c33c

Browse files
committed
Fix elided lifetimes shown as '_ on async functions
1 parent 50a9097 commit 530c33c

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/librustdoc/clean/mod.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,18 @@ impl Clean<Generics> for hir::Generics<'_> {
635635
_ => false,
636636
}
637637
}
638+
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
639+
///
640+
/// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
641+
///
642+
/// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
643+
fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
644+
match param.kind {
645+
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided } => true,
646+
_ => false,
647+
}
648+
}
649+
638650
let impl_trait_params = self
639651
.params
640652
.iter()
@@ -653,7 +665,7 @@ impl Clean<Generics> for hir::Generics<'_> {
653665
.collect::<Vec<_>>();
654666

655667
let mut params = Vec::with_capacity(self.params.len());
656-
for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
668+
for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
657669
let p = p.clean(cx);
658670
params.push(p);
659671
}
@@ -1433,7 +1445,16 @@ impl Clean<Type> for hir::Ty<'_> {
14331445
TyKind::Never => Never,
14341446
TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)),
14351447
TyKind::Rptr(ref l, ref m) => {
1436-
let lifetime = if l.is_elided() { None } else { Some(l.clean(cx)) };
1448+
// There are two times a `Fresh` lifetime can be created:
1449+
// 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
1450+
// 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
1451+
// See commit 749349fc9f7b12f212bca9ba2297e463328cb701 for more information.
1452+
// Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
1453+
// Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
1454+
// there's no case where it could cause the function to fail to compile.
1455+
let elided =
1456+
l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
1457+
let lifetime = if elided { None } else { Some(l.clean(cx)) };
14371458
BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
14381459
}
14391460
TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),

src/test/rustdoc/async-fn.rs

+29
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// ignore-tidy-linelength
12
// edition:2018
23
#![feature(min_const_generics)]
34

@@ -52,3 +53,31 @@ pub trait Trait<const N: usize> {}
5253
// @has async_fn/fn.const_generics.html
5354
// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
5455
pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
56+
57+
// test that elided lifetimes are properly elided and not displayed as `'_`
58+
// regression test for #63037
59+
// @has async_fn/fn.elided.html
60+
// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
61+
pub async fn elided(foo: &str) -> &str {}
62+
// This should really be shown as written, but for implementation reasons it's difficult.
63+
// See `impl Clean for TyKind::Rptr`.
64+
// @has async_fn/fn.user_elided.html
65+
// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
66+
pub async fn user_elided(foo: &'_ str) -> &str {}
67+
// @has async_fn/fn.static_trait.html
68+
// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
69+
pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
70+
// @has async_fn/fn.lifetime_for_trait.html
71+
// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
72+
pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
73+
74+
struct AsyncFdReadyGuard<'a, T> { x: &'a T }
75+
76+
impl Foo {
77+
// @has async_fn/struct.Foo.html
78+
// @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
79+
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
80+
// taken from `tokio` as an example of a method that was particularly bad before
81+
// @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
82+
pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
83+
}

0 commit comments

Comments
 (0)