Skip to content

Commit

Permalink
Rollup merge of #80319 - jyn514:async-lifetimes, r=tmandry
Browse files Browse the repository at this point in the history
Fix elided lifetimes shown as `'_` on async functions

Closes #63037.

r? `@tmandry` on the implementation, `@Darksonn` on the test cases.
  • Loading branch information
Dylan-DPC authored Dec 25, 2020
2 parents c24fcad + ceb66ad commit d837407
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 2 deletions.
25 changes: 23 additions & 2 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,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()
Expand All @@ -656,7 +668,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);
}
Expand Down Expand Up @@ -1437,7 +1449,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 #59286 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)),
Expand Down
44 changes: 44 additions & 0 deletions src/test/rustdoc/async-fn.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore-tidy-linelength
// edition:2018
#![feature(min_const_generics)]

Expand Down Expand Up @@ -48,7 +49,50 @@ impl Foo {
pub async fn mut_self(mut self, mut first: usize) {}
}

pub trait Pattern<'a> {}

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 + '_> {}
// @has async_fn/fn.elided_in_input_trait.html
// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}

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>, ()> {}
// @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
pub async fn mut_self(&mut self) {}
}

// test named lifetimes, just in case
// @has async_fn/fn.named.html
// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
// @has async_fn/fn.named_trait.html
// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}

0 comments on commit d837407

Please sign in to comment.