::fix_hidden_lifetime_bug
rust,ignore
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> examples/main.rs:13:40
|
13 | fn foo<'a, 'b>(it: &'a mut &'b ()) -> impl 'a + Sized {
| ^^^^^^^^^^^^^^^
|
note: hidden type `&'a mut &'b ()` captures the lifetime `'b` as defined on the function body at 13:12
--> examples/main.rs:13:12
|
13 | fn foo<'a, 'b>(it: &'a mut &'b ()) -> impl 'a + Sized {
| ^^
Problematic code
rust,compile_fail
fn foo<'a, 'b>(it: &'a mut &'b ()) -> impl 'a + Sized {
it
}
rust,ignore
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> examples/main.rs:8:45
|
8 | async fn bar<'a> (_: &(), _: Box<dyn Send>) {
| ^
|
note: hidden type `impl Future` captures lifetime smaller than the function body
--> examples/main.rs:8:45
|
8 | async fn bar<'a> (_: &(), _: Box<dyn Send>) {
| ^
Problematic code
rust,compile_fail
async fn bar<'a> (_: &(), _: Box<dyn Send>) {
/* … */
}
rust,ignore
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> examples/main.rs:4:57
|
4 | async fn baz<'a>(a: &'static (), b: &(), c: &()) {
| ^
|
note: hidden type `impl Future` captures lifetime smaller than the function body
--> examples/main.rs:4:57
|
4 | async fn baz<'a>(a: &'static (), b: &(), c: &()) {
| ^
Problematic code
rust,compile_fail
async fn baz<'a>(a: &'static (), b: &(), c: &()) {
/* … */
}
Then you can add the attribute provided by this crate to automagically generate an equivalent signature that soothes such a grumpy compiler 🙃
See [the lifetime bug async
issue], as well as this other comment for
more info.
The fix is thus to perform the unsugaring from an async fn
to an fn
yielding a Future
, and then just adding the necessary + Captures<'_>
bounds.
See also this post where I explain the issue more in detail.
cargo add fix_hidden_lifetime_bug
, or add the following to your Cargo.toml
file:
toml
[dependencies]
fix-hidden-lifetime-bug = "x.y.z"
cargo search fix_hidden_lifetime_bug
Add the following to your lib.rs
file:
```rust,ignore
extern crate fixhiddenlifetime_bug; ```
Slap a #[fix_hidden_lifetime_bug]
on the problematic function:
```rust,ignore
fn foo<'a, 'b>(it: &'a mut &'b ()) -> impl 'a + Sized { it } ```
```rust,ignore
async fn baz<'a>(fst: &'static str, snd: &str, thrd: &str) { /* … */ } ```
In the case of methods, the Self
type may be hiding lifetime parameters on
its own, in which case a macro annotation on the method alone may not have
enough syntactical information to generate the fix:
```rust,compilefail use ::fixhiddenlifetimebug::fixhiddenlifetime_bug;
struct Invariant<'lt> ( fn(&()) -> &mut &'lt (), );
impl Invariant<'> { #[fixhiddenlifetimebug] fn quux(&self) -> impl '_ + Sized { self } } ```
In that case, the fix is to also decorate the whole impl
block with
the attribute:
```rust use ::fixhiddenlifetimebug::fixhiddenlifetimebug;
struct Invariant<'lt> ( fn(&()) -> &mut &'lt (), );
impl Invariant<'> { #[fixhiddenlifetimebug] fn quux(&self) -> impl '_ + Sized { self } } ```
By enabling the "showme"
Cargo feature:
toml
[dependencies]
fix-hidden-lifetime-bug.version = "x.y.z"
fix-hidden-lifetime-bug.features = ["showme"]
you can then feed a showme
parameter to specific
#[fix_hidden_lifetime_bug]
annotations, as follows:
```rust,ignore
```
Example
```rust,ignore use ::fixhiddenlifetimebug::fixhiddenlifetimebug;
async fn baz<'a>(a: &'static (), b: &'_ (), c: &'_ ()) { println!("Hello, World!"); } ```
outputs:
rust
fn baz<'a, '_0, '_1, '__async_fut>(
a: &'static (),
b: &'_0 (),
c: &'_1 (),
) -> impl '__async_fut
+ ::fix_hidden_lifetime_bug::core::future::Future<Output = ()>
+ ::fix_hidden_lifetime_bug::Captures<'a>
+ ::fix_hidden_lifetime_bug::Captures<'_0>
+ ::fix_hidden_lifetime_bug::Captures<'_1>
where
&'static (): '__async_fut,
&'_0 (): '__async_fut,
&'_1 (): '__async_fut,
{
async move {
"Mention the input vars so that they get captured by the Future";
let (_, _, _) = (a, b, c);
println!("Hello, World!");
}
}
This will make the attribute display the result of its expansion (and
its expansion only! Hence yielding output that is way more readable than
that from cargo expand
or other such tools), basically showing you how to
manually fix a given function signature if you so wish (e.g., to avoid
depending on proc-macro processing every time the annotated function is
compiled, or to make the life easier for IDEs).
Should you fix the signature, you may then be interested in:
If you don't want to have to recompile each time the proc-macro able to fix
function signatures for you (e.g., you rather want it to [show you how to
fix the signature] so that you can do it through exclusive usage of
+ Captures<'…>
additions), so as not to have to pay the proc-macro
compilation time each time you compile from scratch, then you can opt out of
it by disabling the default-features
of the crate: this will disable the
proc-macros
features, which is the one that brings it to the table.
That way, you can still use this then very lightweight crate just for its
Captures<'…>
(and maybe MentionsTy<…>
) definitions, and the
documentation that goes with it!
toml
[dependencies]
…
fix-hidden-lifetime-bug.version = "x.y.z"
fix-hidden-lifetime-bug.default-features = false