-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Comments
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 |
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 |
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 |
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. |
Hello, is there any progress about this? |
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 |
…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.
I'm getting this issue without async, though it gives a
With nightly 2022-11-08 (before error message change):
Only happens when both constraints are put on the impl. Also solved by removing the Adding |
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.
With
|
This code is also triggering the compilation error that links to this issue, unrelated to 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
} |
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 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 Diagnostics for first code snippet:
|
|
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:
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 |
thanks @nitsky, your 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 |
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 I also found that implementing the future manually returning an |
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 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 |
@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 |
|
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? |
I tried this code:
I expected to see this happen: both type declaration of
IterCaller::call_1
andIterCaller::call_2
pass the compilingInstead, this happened:
Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: