async-graphql
async-graphql copied to clipboard
SimpleObject: error: lifetime may not live long enough
I got some weird error after using #[graphql(complex)]
and #[ComplexObject]
on other struct.
So the affected struct doesn't have the "complex" thing.
I'm probably using nested ComplexObject
that uses some dataloaders.
I'll try to make a minimal, reproducible example.
Expected Behavior
Actual Behavior
13 | #[derive(Debug, PartialEq, SimpleObject)]
| -^^^^^^^^^^^
| |
| let's call the lifetime of this reference `'2`
| let's call the lifetime of this reference `'1`
| associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
| in this derive macro expansion
|
::: /home/bbigras/.cargo/registry/src/github.com-1ecc6299db9ec823/async-graphql-derive-3.0.38/src/lib.rs:47:1
Steps to Reproduce the Problem
Specifications
- Version: 3.0.38
- Platform: NixOS 22.05 (Quokka) x86_64
- Subsystem:
Please provide an example that reproduces this error.
I get the same thing locally since i've updated async-graphql, it happens sporadically
After a clean build it goes away but comes back after a while
After a clean build it goes away but comes back after a while
I had something similar too.
Could you please provide an example that can reproduce this problem?😁
Yes sorry. I'll be back home tomorrow. (I should have still made one earlier as promised when I opened the issue though)
I think I'm able to reproduce. There's a compiler bug, but I'm not sure yet if both problems are related.
error: lifetime may not live long enough
--> src/query.rs:53:26
|
53 | #[derive(Clone, Default, SimpleObject)]
| -^^^^^^^^^^^
| |
| let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`
| associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
= note: this error originates in the derive macro `SimpleObject` (in Nightly builds, run with -Z macro-backtrace for more info)
error: internal compiler error: encountered incremental compilation error with mir_borrowck(async_graphql_900[a851]::query::{impl#16}::name)
|
= help: This is a known issue with the compiler. Run `cargo clean -p async_graphql_900` or `cargo clean` to allow your project to compile
= note: Please follow the instructions below to create a bug report with the provided information
= note: See <https://github.com/rust-lang/rust/issues/84970> for more information
Now I can't reproduce it. I made a backup when it failed, but excluding my target folder.
So I never had the This is a known issue with the compiler. Run
cargo clean -p async_graphql_900 or
message before, but if I try cargo clean -p async_graphql_900
with my real project, the next build is fine.
Should we just assume that it's a bug with the compiler?
Here's my "minimal test case" https://github.com/bbigras/async-graphql-900 , but I can't reproduce the error at will.
EDIT: another weird thing is that I'm using the same compiler for my real project and the test case.
Same on NixOS 22.05
I have met this, run cargo clean first, then this should work.
I have a simple script now for this until there is some workaround as doing cargo clean
just takes way too long for me. The issue happens quite often for me, when the compiler complains about other things beforehand for some reason this issue pops up even though the other issues have been fixed. If your workflow consists of cargo watch -x "run"
and having an autosave in your editor just makes this issue very common.
cargo clean -p async-graphql -p *your crate name*
I'm seeing this as well. I'm wondering whether it's a bug in Rust itself. Not sure exactly how to repro the issue, although I see it quite frequently.
cargo clean
and cargo build
works for me.
To reproduce --
I had async-graphql=3.0.38
and I upgraded to async-graphql=4.0.1
which immediately showed the error in my schema.
Can confirm that it is happening frequently with both async-graphql 3.0.38
and 4.0.1
on both Rust v1.61
and v1.62
@adzialocha It stopped happening. Not able to reproduce now either.
Just started getting this, can't reliably trigger or reliably stop it from happening 😂 cargo clean temporarily fixes it as others said, perhaps something related to compilation order, or something not being recompiled?
async-graphql
and async-graphql-axum
4.0.4
- stable-aarch64-apple-darwin
I've been dealing with this for the past two days to no avail. cargo build -r
works fine, but cargo check
and cargo build (no release mode)
fails. I've also been wondering whether it's got something to do with incremental compilation, but I'm really not sure, since I only get this when using the SimpleObject
macro. I'm running the latest stable release of rustc and latest version of async-graphql
.
I was having this problem as well, and then it went away for good. Not sure what changed.
I am having this problem too, in Rust 1.62.0. But it works fine if I switch back to Rust 1.61.0.
Click to see how I reached that situation
Ok, I have investigated a bit the @Bberky's situation. They managed to reduce the issue to:
#[derive(::async_graphql::SimpleObject)]
pub struct A {
field: String,
}
+ pub struct B { field: String }
with a cargo c
before and after that diff, on 1.62.0
, triggering a lifetime error message as reported by other people in this repo. By using an intermediary expansion trick, I got the expansion of SimpleObject
on A
to be:
Click to see the expansion
#[allow(clippy::all, clippy::pedantic)]
impl A {
#[inline]
#[allow(missing_docs)]
async fn field(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<&String> {
::std::result::Result::Ok(&self.field)
}
}
#[allow(clippy::all, clippy::pedantic)]
#[async_graphql::async_trait::async_trait]
impl async_graphql::resolver_utils::ContainerType for A {
async fn resolve_field(
&self,
ctx: &async_graphql::Context<'_>,
) -> async_graphql::ServerResult<::std::option::Option<async_graphql::Value>> {
if ctx.item.node.name.node == "field" {
let f = async move {
self.field(ctx)
.await
.map_err(|err| err.into_server_error(ctx.item.pos))
};
let obj = f.await.map_err(|err| ctx.set_error_path(err))?;
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
return async_graphql::OutputType::resolve(&obj, &ctx_obj, ctx.item)
.await
.map(::std::option::Option::Some);
}
::std::result::Result::Ok(::std::option::Option::None)
}
}
#[allow(clippy::all, clippy::pedantic)]
#[async_graphql::async_trait::async_trait]
impl async_graphql::OutputType for A {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed("A")
}
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> ::std::string::String {
registry.create_output_type::<Self, _>(
async_graphql::registry::MetaTypeId::Object,
|registry| async_graphql::registry::MetaType::Object {
name: ::std::borrow::Cow::into_owned(::std::borrow::Cow::Borrowed("A")),
description: ::std::option::Option::None,
fields: {
let mut fields = async_graphql::indexmap::IndexMap::new();
fields.insert(
::std::borrow::ToOwned::to_owned("field"),
async_graphql::registry::MetaField {
name: ::std::borrow::ToOwned::to_owned("field"),
description: ::std::option::Option::None,
args: ::std::default::Default::default(),
ty: <String as async_graphql::OutputType>::create_type_info(registry),
deprecation: async_graphql::registry::Deprecation::NoDeprecated,
cache_control: async_graphql::CacheControl {
public: true,
max_age: 0usize,
},
external: false,
provides: ::std::option::Option::None,
requires: ::std::option::Option::None,
visible: ::std::option::Option::None,
compute_complexity: ::std::option::Option::None,
},
);
fields
},
cache_control: async_graphql::CacheControl {
public: true,
max_age: 0usize,
},
extends: false,
keys: ::std::option::Option::None,
visible: ::std::option::Option::None,
is_subscription: false,
rust_typename: ::std::any::type_name::<Self>(),
},
)
}
async fn resolve(
&self,
ctx: &async_graphql::ContextSelectionSet<'_>,
_field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
) -> async_graphql::ServerResult<async_graphql::Value> {
async_graphql::resolver_utils::resolve_container(ctx, self).await
}
}
impl async_graphql::ObjectType for A {}
From there, once that diff is applied in between cargo check
s, I get:
error: lifetime may not live long enough
--> /private/var/folders/m_/347zzk7j6nz08tt6z3tnd3z00000gn/T/tmp.qeHHjilha7/target/debug-proc-macros/test-f4020daedf6df8e8.rs:5:95
|
5 | async fn field(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<&String> {
| ____________________-___________________________________--_____________________________________^
| | | |
| | | let's call the lifetime of this reference `'2`
| | let's call the lifetime of this reference `'1`
6 | | ::std::result::Result::Ok(&self.field)
7 | | }
| |_____^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
error: lifetime may not live long enough
--> /private/var/folders/m_/347zzk7j6nz08tt6z3tnd3z00000gn/T/tmp.qeHHjilha7/target/debug-proc-macros/test-f4020daedf6df8e8.rs:6:9
|
5 | async fn field(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<&String> {
| - -- let's call the lifetime of this reference `'2`
| |
| let's call the lifetime of this reference `'1`
6 | ::std::result::Result::Ok(&self.field)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
So the interesting part is that this does not involve async_trait
whatsoever (I was afraid it would), and so the following part of the expansion is the one hitting the incremental compilation bug:
#[allow(clippy::all, clippy::pedantic)]
impl A {
#[inline]
#[allow(missing_docs)]
async fn field(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<&String> {
::std::result::Result::Ok(&self.field)
}
}
Finally, removing SimpleObject
altogether from the equation, we end up with the following diff in between cargo check
s running into the incremental compilation issue:
pub struct A {
field: String,
}
#[allow(clippy::all, clippy::pedantic)]
impl A {
#[inline]
#[allow(missing_docs)]
async fn field(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<&String> {
::std::result::Result::Ok(&self.field)
}
}
+ pub struct B { field: String, }
which ends up yielding the following stand-alone repro which I'll report to rust [EDIT: done]:
fn main(){let _=std::process::Command::new("/bin/bash").args(&["-c", concat!(r##"{
set -euo pipefail
cd $(mktemp -d)
cargo init -q --name example --lib
cat> src/lib.rs <<'EOF'
#![allow(unused)]
struct Foo;
impl Foo {
async fn f(&self, _: &&()) -> &() {
&()
}
}
EOF
(set -x
cargo c -q
{ set +x; echo 'enum Bar {}'; } 2>/dev/null | tee -a src/lib.rs
cargo c -q
)
echo ✅
} 2>&1"##)]).status();}
In the meantime, @sunli829 (or other maintainers of this crate), you may be able to dodge the compiler limitation by using https://docs.rs/fix-hidden-lifetime-bug
on the non-async_trait
-annotated async fn
s 🙂
Workaround
I've submitted #972 which implements the usage of fix_hidden_lifetime_bug
as a palliative workaround for that compiler regression. To use it, follow the instructions described in that PR.
I was able to fix this issue by simple running export CARGO_INCREMENTAL=0
, requires a better workstation to remain productive but it does work
@ControlCplusControlV you should be able to save in compile times by using that PR through a patch rather than fully disabling incremental altogether 🙂:
[patch.crates-io.async-graphql]
git = "https://github.com/danielhenrymantilla/async-graphql.git"
branch = "workaround-for-1-62-bug"
Here are some hopefully complete but overspecific repro steps:
rustup install nightly-2022-06-30 --force
rustup default nightly-2022-06-30
git clone https://github.com/bkonkle/rust-example-caster-api
cd rust-example-caster-api
cargo build
Edit ./libs/shows/src/episodes_service.rs:
diff --git a/libs/shows/src/episodes_service.rs b/libs/shows/src/episodes_service.rs
index a1b4c9f..e7dfddd 100644
--- a/libs/shows/src/episodes_service.rs
+++ b/libs/shows/src/episodes_service.rs
@@ -70,20 +70,7 @@ impl DefaultEpisodesService {
#[async_trait]
impl EpisodesService for DefaultEpisodesService {
async fn get(&self, id: &str, with_show: &bool) -> Result<Option<Episode>> {
- let query = episode_model::Entity::find_by_id(id.to_owned());
-
- let episode = if *with_show {
- query
- .find_also_related(show_model::Entity)
- .one(&*self.db)
- .await?
- } else {
- query.one(&*self.db).await?.map(|u| (u, None))
- };
-
- let episode: EpisodeOption = episode.into();
-
- Ok(episode.into())
+ Ok(None)
}
async fn get_by_ids(&self, ids: Vec<String>) -> Result<Vec<Episode>> {
cargo build # (assuming you didn't wrap cargo or turn off incremental builds)
and you'll see
error: lifetime may not live long enough
--> libs/shows/src/show_model.rs:9:77
|
9 | Clone, Debug, Eq, PartialEq, DeriveEntityModel, Deserialize, Serialize, SimpleObject, PolarClass,
| -^^^^^^^^^^^
| |
| let's call the lifetime of this reference `'2`
| let's call the lifetime of this reference `'1`
| associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
|
= note: this error originates in the derive macro `SimpleObject` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider introducing a named lifetime parameter and update trait if needed
|
9 ~ Clone, Debug, Eq, PartialEq, DeriveEntityModel, Deserialize, Serialize, 'a'aimpleObject, PolarClass,
10| )]
...
16| #[polar(attribute)]
17~ pub id<'a>: String,
|
If you rm -rf target, it will then build fine.
This is probably fixed now in Rust 1.62.1: https://github.com/rust-lang/rust/issues/98890
I tested my https://github.com/async-graphql/async-graphql/issues/900#issuecomment-1175787840 to confirm nightly-2022-07-23 (rustc 1.64.0-nightly (848090dcd 2022-07-22)
) is fixed.
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
This issue was closed because it has been stalled for 5 days with no activity.