Skip to content

Async function on graphql_object with lifetime #875

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
TilBlechschmidt opened this issue Feb 13, 2021 · 1 comment
Closed

Async function on graphql_object with lifetime #875

TilBlechschmidt opened this issue Feb 13, 2021 · 1 comment
Assignees
Labels
bug Something isn't working k::api Related to API (application interface)

Comments

@TilBlechschmidt
Copy link

Describe the bug
When defining a struct, giving it a lifetime and then writing a impl block with the graphql_object macro containing a async function which accesses anything from self, the compiler starts complaining that Sync from somewhere deep in the graphql_object macro is less specific than Sync (wherever that comes from).

error[E0308]: mismatched types
   --> src/main.rs:5:1
    |
54  | #[graphql_object(context = Context)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | |
    | one type is more general than the other
    | in this macro invocation
    |
   ::: /[...]/.cargo/git/checkouts/juniper-29ae65ca2e7a9997/a9f6464/juniper_codegen/src/lib.rs:467:1
    |
467 | pub fn graphql_object(args: TokenStream, input: TokenStream) -> TokenStream {
    | --------------------------------------------------------------------------- in this expansion of `#[graphql_object]`
    |
    = note: expected type `Sync`
               found type `Sync`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

To Reproduce
Take the lifetime example from the graphql_object documentation and make the function async. Bit of a silly example as it does not have to be async but it proves the point (same thing happens when you actually use more complex async tasks).
Here is the bare-bones code snippet to reproduce the error:

struct WithLifetime<'a> {
    value: &'a str,
}

#[juniper::graphql_object]
impl<'a> WithLifetime<'a> {
    async fn value(&self) -> &str {
        self.value
    }
}

Expected behavior
I'd expect it to work just the same with async as long as the reference to the object is retained in the place where the function is called 🤷

@TilBlechschmidt TilBlechschmidt added bug Something isn't working needs-triage labels Feb 13, 2021
@tyranron
Copy link
Member

I think this happens due to #[graphql_object] macro desugars its method to closures:

#[graphql_object]
impl<'a> WithLifetime<'a> {
    async fn value(&self) -> &str {
        self.value
    }
}

// desugars in resolver code to something like this:
let res = executor.resolve_field(|| self.value);

And when lifetimes are involved, Rust usually generates types for closures using HRTBs: for<'a>. And that's the point where "less specific" error comes from.

Potentially, it should be fixed if #[graphql_object] macro will use direct method calls instead of generating closures, like #[graphql_interface] does. Though, the later doesn't have this problem.

@tyranron tyranron added k::api Related to API (application interface) and removed needs-triage labels Jul 19, 2021
@tyranron tyranron self-assigned this Jul 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working k::api Related to API (application interface)
Projects
None yet
Development

No branches or pull requests

2 participants