Crates.io | fix-hidden-lifetime-bug |
lib.rs | fix-hidden-lifetime-bug |
version | 0.2.7 |
source | src |
created_at | 2021-05-18 21:00:16.223448 |
updated_at | 2024-08-11 14:34:43.055253 |
description | Proc-macro to write an automatic fix for the "hidden lifetime in impl Trait" issue |
homepage | |
repository | https://github.com/danielhenrymantilla/fix-hidden-lifetime-bug.rs |
max_upload_size | |
id | 399142 |
size | 62,438 |
::fix_hidden_lifetime_bug
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 {
| ^^
fn foo<'a, 'b>(it: &'a mut &'b ()) -> impl 'a + Sized {
it
}
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>) {
| ^
async fn bar<'a> (_: &(), _: Box<dyn Send>) {
/* … */
}
EDIT: Fixed as of 1.69.0
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: &()) {
| ^
async fn baz<'a>(a: &'static (), b: &(), c: &()) {
/* … */
}
EDIT: Fixed as of 1.69.0
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:
[dependencies]
fix-hidden-lifetime-bug = "x.y.z"
cargo search fix_hidden_lifetime_bug
Add the following to your lib.rs
file:
#[macro_use]
extern crate fix_hidden_lifetime_bug;
Slap a #[fix_hidden_lifetime_bug]
on the problematic function:
#[fix_hidden_lifetime_bug] // <-- Add this!
fn foo<'a, 'b>(it: &'a mut &'b ()) -> impl 'a + Sized {
it
}
#[fix_hidden_lifetime_bug] // <-- Add this!
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:
use ::fix_hidden_lifetime_bug::fix_hidden_lifetime_bug;
struct Invariant<'lt> (
fn(&()) -> &mut &'lt (),
);
impl Invariant<'_> {
#[fix_hidden_lifetime_bug]
fn quux(&self) -> impl '_ + Sized { self }
}
In that case, the fix is to also decorate the whole impl
block with
the attribute:
use ::fix_hidden_lifetime_bug::fix_hidden_lifetime_bug;
struct Invariant<'lt> (
fn(&()) -> &mut &'lt (),
);
#[fix_hidden_lifetime_bug]
impl Invariant<'_> {
#[fix_hidden_lifetime_bug]
fn quux(&self) -> impl '_ + Sized { self }
}
By enabling the "showme"
Cargo feature:
[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:
#[fix_hidden_lifetime_bug(showme)]
use ::fix_hidden_lifetime_bug::fix_hidden_lifetime_bug;
#[fix_hidden_lifetime_bug(showme)]
async fn baz<'a>(a: &'static (), b: &'_ (), c: &'_ ()) {
println!("Hello, World!");
}
outputs:
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) = (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!
[dependencies]
…
fix-hidden-lifetime-bug.version = "x.y.z"
fix-hidden-lifetime-bug.default-features = false