Skip to content
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

Unexpected higher-ranked lifetime error in GAT usage #100013

Open
ethe opened this issue Aug 1, 2022 · 26 comments
Open

Unexpected higher-ranked lifetime error in GAT usage #100013

ethe opened this issue Aug 1, 2022 · 26 comments
Assignees
Labels
A-async-await Area: Async & Await A-coroutines Area: Coroutines A-lifetimes Area: lifetime related AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs S-has-mcve Status: A Minimal Complete and Verifiable Example has been found for this issue T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@ethe
Copy link

ethe commented Aug 1, 2022

I tried this code:

#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]

use std::future::Future;

pub trait FutureIterator: 'static {
    type Iterator;

    type Future<'s, 'cx>: Future<Output = Self::Iterator> + Send + 'cx
    where
        's: 'cx;

    fn get_iter<'s, 'cx>(&'s self, info: &'cx ()) -> Self::Future<'s, 'cx>;
}

trait IterCaller: 'static {
    type Future1<'cx>: Future<Output = ()> + Send + 'cx;
    type Future2<'cx>: Future<Output = ()> + Send + 'cx;

    fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx>
    where
        's: 'cx;
    fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx>
    where
        's: 'cx;
}

struct UseIter<FI1, FI2> {
    fi_1: FI1,
    fi_2: FI2,
}

impl<FI1, FI2> IterCaller for UseIter<FI1, FI2>
where
    FI1: FutureIterator + 'static + Send + Sync,
    for<'s, 'cx> FI1::Future<'s, 'cx>: Send,
    FI2: FutureIterator + 'static + Send + Sync,
{
    type Future1<'cx> = impl Future<Output = ()> + Send + 'cx
    where
        Self: 'cx;

    type Future2<'cx> = impl Future<Output = ()> + Send + 'cx
    where
        Self: 'cx;

    fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx>
    where
        's: 'cx,
    {
        async {
            self.fi_1.get_iter(cx).await;
        }
    }

    fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx>
    where
        's: 'cx,
    {
        async {
            self.fi_2.get_iter(cx).await;
        }
    }
}

fn main() {}

I expected to see this happen: both type declaration of IterCaller::call_1 and IterCaller::call_2 pass the compiling

Instead, this happened:

error: higher-ranked lifetime error
  --> src/main.rs:60:9
   |
60 | /         async {
61 | |             self.fi_2.get_iter(cx).await;
62 | |         }
   | |_________^

Meta

rustc --version --verbose:

rustc 1.64.0-nightly (f9cba6374 2022-07-31)
binary: rustc
commit-hash: f9cba63746d0fff816250b2ba7b706b5d4dcf000
commit-date: 2022-07-31
host: x86_64-unknown-linux-gnu
release: 1.64.0-nightly
LLVM version: 14.0.6
@ethe ethe added the C-bug Category: This is a bug. label Aug 1, 2022
@aliemjay
Copy link
Member

aliemjay commented Aug 1, 2022

This is another manifestation of #92096.

Minimized:

#![feature(generic_associated_types)]

pub trait FutureIterator {
    type Future<'s, 'cx>: Send
    where
        's: 'cx;
}

fn call_2<I: FutureIterator>() -> impl Send {
    async { // a generator checked for autotrait impl `Send`
        let x = None::<I::Future<'_, '_>>; // a type referencing GAT
        async {}.await; // a yield point
    }
}

@rustbot label F-generic_associated_types A-async-await A-lifetimes A-generators T-types

@rustbot rustbot added A-async-await Area: Async & Await A-coroutines Area: Coroutines A-lifetimes Area: lifetime related F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs T-types Relevant to the types team, which will review and decide on the PR/issue. labels Aug 1, 2022
@tmandry
Copy link
Member

tmandry commented Aug 15, 2022

This is an unfortunate error message. Since GATs is close to stabilization, does it make sense to nominate for types team discussion?

@rustbot label +I-types-nominated

@rustbot rustbot added the I-types-nominated Nominated for discussion during a types team meeting. label Aug 15, 2022
@eholk
Copy link
Contributor

eholk commented Aug 15, 2022

Yeah, I'd like to hear from the types team on this. @nikomatsakis or @jackh726, is adding I-types-nominated the way to do that?

@rustbot label +AsyncAwait-Triaged

@rustbot rustbot added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label Aug 15, 2022
@jackh726
Copy link
Member

jackh726 commented Oct 7, 2022

This error message sucks, but is likely related to TAITs. Nevertheless, I'm going to take some time this upcoming week (I think) to take a look at least to improve the error message.

@jackh726 jackh726 added F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` S-has-mcve Status: A Minimal Complete and Verifiable Example has been found for this issue and removed I-types-nominated Nominated for discussion during a types team meeting. labels Oct 7, 2022
@jackh726 jackh726 self-assigned this Oct 7, 2022
@PureWhiteWu
Copy link

Hello, is there any progress about this?

@chrysn
Copy link
Contributor

chrysn commented Nov 8, 2022

I'm seeing a similar message when using elaborate GAT-heavy traits; it's far from a minimal example as it is now, but there's no async block or function involved. Is there value in attempting to minimize the example, or is the underlying problem of this error appearing without any apparent cause understood well enough already (so that I'd just wait for the fix, and only revisit if this issue gets closed and mine persists)?

@jackh726
Copy link
Member

jackh726 commented Nov 9, 2022

@chrysn if there is no async, then I expect that to be a separate problem. So probably worth minimizing. (#103171 should give a bit nicer error for the current issue, so you can also wait to see if the error message changes for yours too)

bors added a commit to rust-lang-ci/rust that referenced this issue Nov 9, 2022
…cjgillot

Better error for HRTB error from generator interior

cc rust-lang#100013

This is just a first pass at an error. It could be better, and shouldn't really be emitted in the first place. But this is better than what was being emitted before.
@samlich
Copy link
Contributor

samlich commented Feb 19, 2023

I'm getting this issue without async, though it gives a lifetime bound not satisfied, instead of a higher-ranked lifetime error.

Playground

trait Tr {
        type A<'a, 'b: 'a>;
}

struct S<T> {
        a: T,
}

// bad
impl<T: Tr> S<T>
where
        for<'a, 'b> T: Tr<A<'a, 'b> = ()>,
        for<'c, 'd> T::A<'c, 'd>: Default,
{
}
error: lifetime bound not satisfied
  --> src/lib.rs:10:1
   |
10 | / impl<T: Tr> S<T>
11 | | where
12 | |     for<'a, 'b> T: Tr<A<'a, 'b> = ()>,
13 | |     for<'c, 'd> T::A<'c, 'd>: Default,
14 | | {
15 | | }
   | |_^
   |
note: the lifetime `'c` defined here...
  --> src/lib.rs:13:6
   |
13 |     for<'c, 'd> T::A<'c, 'd>: Default,
   |         ^^
note: ...must outlive the lifetime `'d` defined here
  --> src/lib.rs:13:10
   |
13 |     for<'c, 'd> T::A<'c, 'd>: Default,
   |             ^^
   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)

With nightly 2022-11-08 (before error message change):

error[E0478]: lifetime bound not satisfied
  --> src/lib.rs:10:1
   |
10 | / impl<T: Tr> S<T>
11 | | where
12 | |     for<'a, 'b> T: Tr<A<'a, 'b> = ()>,
13 | |     for<'c, 'd> T::A<'c, 'd>: Default,
14 | | {
15 | | }
   | |_^

Only happens when both constraints are put on the impl. Also solved by removing the 'b: 'a constraint on C.

Adding 'a: 'b to C causes it to also complain that 'd must outlive 'c. I don't understand why they're reversed.

@tlowerison
Copy link

I've also ran into this issue without async. Interestingly, the correct implied lifetime bound seems to be getting used when a struct is used to impose the bound as opposed to a GAT.

Playground

struct B<'a: 'b, 'b>(&'b &'a ());

trait Foo {
    type Bar<'a, 'b>
    where
        'a: 'b;

    fn suceeds1<F, T>(&self, f: F) -> T
    where
        F: for<'a, 'b> FnOnce(&'b B<'a, 'b>) -> T;

    fn succeeds2(&self)
    where
        for<'a, 'b> B<'a, 'b>: Default;

    fn fails1<F, T>(&self, f: F) -> T
    where
        F: for<'a, 'b> FnOnce(&'b Self::Bar<'a, 'b>) -> T;

    fn fails2(&self)
    where
        for<'a, 'b> Self::Bar<'a, 'b>: Default;
}

impl Foo for () {
    type Bar<'a, 'b> = B<'a, 'b> where 'a: 'b;

    fn suceeds1<F, T>(&self, f: F) -> T
    where
        F: for<'a, 'b> FnOnce(&'b B<'a, 'b>) -> T,
    {
        todo!()
    }

    fn succeeds2(&self)
    where
        for<'a, 'b> B<'a, 'b>: Default,
    {
        todo!()
    }

    fn fails1<F, T>(&self, f: F) -> T
    where
        F: for<'a, 'b> FnOnce(&'b Self::Bar<'a, 'b>) -> T,
    {
        todo!()
    }

    fn fails2(&self)
    where
        for<'a, 'b> Self::Bar<'a, 'b>: Default,
    {
        todo!()
    }
}

With nightly-2023-03-07-aarch64-apple-darwin toolchain and on playground I get

error: lifetime bound not satisfied
  --> src/lib.rs:42:8
   |
42 |     fn fails1<F, T>(&self, f: F) -> T
   |        ^^^^^^
   |
note: the lifetime `'b` defined here...
  --> src/lib.rs:44:20
   |
44 |         F: for<'a, 'b> FnOnce(&'b Self::Bar<'a, 'b>) -> T,
   |                    ^^
note: ...must outlive the lifetime `'a` defined here
  --> src/lib.rs:44:16
   |
44 |         F: for<'a, 'b> FnOnce(&'b Self::Bar<'a, 'b>) -> T,
   |                ^^
   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)

error: lifetime bound not satisfied
  --> src/lib.rs:49:8
   |
49 |     fn fails2(&self)
   |        ^^^^^^
   |
note: the lifetime `'b` defined here...
  --> src/lib.rs:51:17
   |
51 |         for<'a, 'b> Self::Bar<'a, 'b>: Default,
   |                 ^^
note: ...must outlive the lifetime `'a` defined here
  --> src/lib.rs:51:13
   |
51 |         for<'a, 'b> Self::Bar<'a, 'b>: Default,
   |             ^^
   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)

error: could not compile `gat-lifetime-error` due to 2 previous errors

@urben1680
Copy link

urben1680 commented Mar 30, 2023

This code is also triggering the compilation error that links to this issue, unrelated to async:

trait Foo {
    type Bar<'a: 'b, 'b>;
    fn baz(_f: impl for<'a, 'b> Fn(Self::Bar<'a, 'b>)) {} //ok
}

impl Foo for () {
    type Bar<'a: 'b, 'b> = ();
    fn baz(_f: impl for<'a, 'b> Fn(Self::Bar<'a, 'b>)) {} //fails
}

@nandesu-utils
Copy link

nandesu-utils commented May 2, 2023

A weird RPITIT error with lifetime bounds. This one fails to borrow check with outlives-bound.

#![feature(return_position_impl_trait_in_trait)]

use std::future::Future;

pub trait Foo: Sync {
    fn run<'a, 'b: 'a, T: Sync>(&'a self, _: &'b T) -> impl Future<Output = ()> + 'a + Send; // doesn't compile
    // fn run<'a, 'b, T: Sync>(&'a self, _: &'b T) -> impl Future<Output = ()> + 'a + Send; // compiles
}

pub trait FooExt: Foo {
    fn run_via<'a, 'b: 'a, T: Sync>(&'a self, t: &'b T) -> impl Future<Output = ()> + 'a + Send {
        async move {
            // asks for an unspecified lifetime to outlive itself? weird diagnostics
            self.run(t).await;
        }
    }
}

However I think this is really weird that if we remove Send bounds everywhere in RPITITs, it will work.

pub trait Foo: Sync {
    fn run<'a, 'b: 'a, T: Sync>(&'a self, _: &'b T) -> impl Future<Output = ()> + 'a;
}

pub trait FooExt: Foo {
    fn run_via<'a, 'b: 'a, T: Sync>(&'a self, t: &'b T) -> impl Future<Output = ()> + 'a {
        async move {
            self.run(t).await; // compiles now!
        }
    }
}

Seems like proving Send breaks it. A type-erased Pin<Box<...>> (no RPITITs) works flawlessly however.

Diagnostics for first code snippet:

error: lifetime bound not satisfied
  --> src/lib.rs:12:9
   |
12 | /         async move {
13 | |             // asks for an unspecified lifetime to outlive itself? weird diagnostics
14 | |             self.run(t).await;
15 | |         }
   | |_________^
   |
note: the lifetime defined here...
  --> src/lib.rs:14:18
   |
14 |             self.run(t).await;
   |                  ^^^
note: ...must outlive the lifetime defined here
  --> src/lib.rs:14:18
   |
14 |             self.run(t).await;
   |                  ^^^
   = note: this is a known limitation that will be removed in the future ([see issue #100013 <https://github.com/rust-lang/rust/issues/100013>](https://github.com/rust-lang/rust/issues/100013) for more information)

@kellpossible
Copy link

I've been unable to use https://github.com/a1akris/page-turner/ version 1.0.0 without encountering this error.

My current workaround is wrapping the pages stream in:

pub fn assert_send_stream<R>(
    s: impl futures::Stream<Item = R> + Send,
) -> impl futures::Stream<Item = R> + Send {
    s
}

@AlirezaDarbandi
Copy link

I tried this code:

#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]

use std::future::Future;

pub trait FutureIterator: 'static {
    type Iterator;

    type Future<'s, 'cx>: Future<Output = Self::Iterator> + Send + 'cx
    where
        's: 'cx;

    fn get_iter<'s, 'cx>(&'s self, info: &'cx ()) -> Self::Future<'s, 'cx>;
}

trait IterCaller: 'static {
    type Future1<'cx>: Future<Output = ()> + Send + 'cx;
    type Future2<'cx>: Future<Output = ()> + Send + 'cx;

    fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx>
    where
        's: 'cx;
    fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx>
    where
        's: 'cx;
}

struct UseIter<FI1, FI2> {
    fi_1: FI1,
    fi_2: FI2,
}

impl<FI1, FI2> IterCaller for UseIter<FI1, FI2>
where
    FI1: FutureIterator + 'static + Send + Sync,
    for<'s, 'cx> FI1::Future<'s, 'cx>: Send,
    FI2: FutureIterator + 'static + Send + Sync,
{
    type Future1<'cx> = impl Future<Output = ()> + Send + 'cx
    where
        Self: 'cx;

    type Future2<'cx> = impl Future<Output = ()> + Send + 'cx
    where
        Self: 'cx;

    fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx>
    where
        's: 'cx,
    {
        async {
            self.fi_1.get_iter(cx).await;
        }
    }

    fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx>
    where
        's: 'cx,
    {
        async {
            self.fi_2.get_iter(cx).await;
        }
    }
}

fn main() {}

I expected to see this happen: both type declaration of IterCaller::call_1 and IterCaller::call_2 pass the compiling

Instead, this happened:

error: higher-ranked lifetime error
  --> src/main.rs:60:9
   |
60 | /         async {
61 | |             self.fi_2.get_iter(cx).await;
62 | |         }
   | |_________^

Meta

rustc --version --verbose:

rustc 1.64.0-nightly (f9cba6374 2022-07-31)
binary: rustc
commit-hash: f9cba63746d0fff816250b2ba7b706b5d4dcf000
commit-date: 2022-07-31
host: x86_64-unknown-linux-gnu
release: 1.64.0-nightly
LLVM version: 14.0.6

@nitsky
Copy link

nitsky commented Apr 12, 2024

I recently encountered this issue with the following code:

use std::future::Future;

trait Trait: Sync {
    type T<'a>: Default;
    fn f(&self, t: Self::T<'_>) -> impl Future<Output = ()> + Send;
}

fn g(t: &impl Trait) -> impl Future<Output = ()> + Send + '_ {
    async {
        t.f(Default::default()).await
    }
}

The error can be avoided with any of the following changes:

  1. Removing the lifetime from the associated type.
  2. Removing the Send bound from the return type.
  3. Returning the future directly rather than awaiting it in an async block.

In my application, I found it easiest to work around the issue by boxing the future.

-        t.f(Default::default()).await
+        use futures::FutureExt;
+        t.f(Default::default()).boxed().await

Note that the '_ bound will no longer be necessary with the 2024 capture rules.

@rvolosatovs
Copy link

I recently encountered this issue with the following code:

use std::future::Future;

trait Trait: Sync {
    type T<'a>: Default;
    fn f(&self, t: Self::T<'_>) -> impl Future<Output = ()> + Send;
}

fn g(t: &impl Trait) -> impl Future<Output = ()> + Send + '_ {
    async {
        t.f(Default::default()).await
    }
}

The error can be avoided with any of the following changes:

1. Removing the lifetime from the associated type.

2. Removing the Send bound from the return type.

3. Returning the future directly rather than awaiting it in an async block.

In my application, I found it easiest to work around the issue by boxing the future.

-        t.f(Default::default()).await
+        use futures::FutureExt;
+        t.f(Default::default()).boxed().await

Note that the '_ bound will no longer be necessary with the 2024 capture rules.

thanks @nitsky, your boxed() observation really helped me to debug this and I found a workaround that does not require a heap allocation:

pub trait SendFuture: core::future::Future {
    fn send(self) -> impl core::future::Future<Output = Self::Output> + Send
    where
        Self: Sized + Send,
    {
        self
    }
}

impl<T: core::future::Future> SendFuture for T {}

my reproducer looks like the following:

    trait X {
        fn test<Y>(&self, x: impl AsRef<[Y]>) -> impl core::future::Future<Output = ()> + Send
        where
            Y: AsRef<str>;
    }

    fn call_test(x: impl X + Send + Sync) -> impl core::future::Future<Output = ()> + Send {
        async move { x.test(["test"]).await }
        // fix:
        // use send_future::SendFuture as _;
        // async move { x.test(["test"]).send().await }
    }

I've published this trait in send-future crate with docs available here: https://docs.rs/send-future/latest/send_future/trait.SendFuture.html

@kanpov
Copy link

kanpov commented Jul 15, 2024

This error pops up for me in the following context:

pub async fn read_pid(filesystem: &impl LinuxFilesystem, pid_file: String) -> Option<u32> {
    let pid_path = OsString::from(pid_file);
    let pid_path = pid_path.as_os_str();
    #[allow(unused)]
    let mut pid_option = None;

    loop {
        if let Ok(reader) = filesystem.open_file(pid_path, &LinuxOpenOptions::new().read()).await {
            tokio::pin!(reader);

            let mut content = String::new();
            if reader.read_to_string(&mut content).await.is_err() {
                continue;
            }

            pid_option = content.parse().ok();
            if pid_option.is_some() {
                break;
            }
        }
    }

    pid_option
}

And when calling that async fn with a correct self as the first argument. Is there any way to work around this? Without send-future, I get 2 errors: this one and "implementation of Send is not general enough"

@rvolosatovs
Copy link

This error pops up for me in the following context:

pub async fn read_pid(filesystem: &impl LinuxFilesystem, pid_file: String) -> Option<u32> {
    let pid_path = OsString::from(pid_file);
    let pid_path = pid_path.as_os_str();
    #[allow(unused)]
    let mut pid_option = None;

    loop {
        if let Ok(reader) = filesystem.open_file(pid_path, &LinuxOpenOptions::new().read()).await {
            tokio::pin!(reader);

            let mut content = String::new();
            if reader.read_to_string(&mut content).await.is_err() {
                continue;
            }

            pid_option = content.parse().ok();
            if pid_option.is_some() {
                break;
            }
        }
    }

    pid_option
}

And when calling that async fn with a correct self as the first argument. Is there any way to work around this? Without send-future, I get 2 errors: this one and "implementation of Send is not general enough"

It looks like a quick fix could be wrapping the filesystem parameter type into an Arc to get rid of the lifetime?

I also found that implementing the future manually returning an impl Future usually helps (and if you do you might want to use the Captures trait bound trick for the borrows)

@kanpov
Copy link

kanpov commented Jul 15, 2024

This error pops up for me in the following context:

pub async fn read_pid(filesystem: &impl LinuxFilesystem, pid_file: String) -> Option<u32> {
    let pid_path = OsString::from(pid_file);
    let pid_path = pid_path.as_os_str();
    #[allow(unused)]
    let mut pid_option = None;

    loop {
        if let Ok(reader) = filesystem.open_file(pid_path, &LinuxOpenOptions::new().read()).await {
            tokio::pin!(reader);

            let mut content = String::new();
            if reader.read_to_string(&mut content).await.is_err() {
                continue;
            }

            pid_option = content.parse().ok();
            if pid_option.is_some() {
                break;
            }
        }
    }

    pid_option
}

And when calling that async fn with a correct self as the first argument. Is there any way to work around this? Without send-future, I get 2 errors: this one and "implementation of Send is not general enough"

It looks like a quick fix could be wrapping the filesystem parameter type into an Arc to get rid of the lifetime?

I also found that implementing the future manually returning an impl Future usually helps (and if you do you might want to use the Captures trait bound trick for the borrows)

The arc approach is not possible due to the method calling this function accepting &self on a non-arced instance per design.

Implementing the future manually was nightmarish and caused a barrage of issues: async block cannot be Send due to content being held across an await point plus lifetime issues, unfortunately it's not possible to not use the &impl LinuxFilesystem reference in my case. Then when the function compiles like so:

pub fn read_pid<F: LinuxFilesystem + Sync>(filesystem: &F, pid_file: String) -> impl Future<Output = Option<u32>> + '_ {
    async move {
        let pid_path = OsString::from(pid_file);
        let pid_path = pid_path.as_os_str();
        #[allow(unused)]
        let mut pid_option = None;

        loop {
            if let Ok(reader) = filesystem.open_file(pid_path, &LinuxOpenOptions::new().read()).await {
                tokio::pin!(reader);
                let mut content = String::new();
                if reader.read_to_string(&mut content).await.is_err() {
                    continue;
                }

                pid_option = content.parse().ok();
                if pid_option.is_some() {
                    break;
                }
            }
        }

        pid_option
    }
}

Calling it produces lifetime bound not satisfied and implementation of Send is not general enough, so this is just a nightmare and not the first time Rust quirks have led to me basically ctrl+c ctrl+v-ing chunks of code.

Returning a Send future and accepting a pin of the reference resolves compilation issues when calling, but now F doesn't live long enough, plus lifetime bound not satisfied.

pub fn read_pid<F: LinuxFilesystem + Sync>(
    filesystem: Pin<&F>,
    pid_file: String,
) -> impl Future<Output = Option<u32>> + Send + '_ {

It should not be necessary for me to refactor a method accepting &self (and working perfectly with &self when this code is not extracted out) into a hack like &self: Arc<Self> just to get it to compile. I'm not even using impl trait argument anymore, just a generic, I've even added a pin. Pinning and boxing the future with BoxFuture didn't help (even though I had to do this awful hack for async closures to not utterly collapse, it's enough that async traits need boxing of everything to even be usable as trait objects)

@rvolosatovs
Copy link

@kanpov your original example seems to work in playground https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e816de3c132cfd2563821a4cc9e90ef3

if you use any generic types in return or parameter position, you probably want to mark them Send and 'static

@kanpov
Copy link

kanpov commented Jul 15, 2024

@kanpov your original example seems to work in playground https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e816de3c132cfd2563821a4cc9e90ef3

if you use any generic types in return or parameter position, you probably want to mark them Send and 'static

  1. read_pid is not inside the LinuxFilesystem trait
  2. Actually calling the function in a &self function while passing in self produces the "lifetime bound not satisfied" and "implementation of Send is not general enough" errors.

@ethe
Copy link
Author

ethe commented Jul 16, 2024

Hi all, since this issue is referenced in the rustc error message, I think the title "Unexpected higher-ranked lifetime error in GAT unsafe" is not clear enough. Shall we edit the title of this issue to make it clearer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-coroutines Area: Coroutines A-lifetimes Area: lifetime related AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug. F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs S-has-mcve Status: A Minimal Complete and Verifiable Example has been found for this issue T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests