-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Closures which return a reference that depends on an argument unconditionally fail borrow checking #111662
Comments
This is an issue with the algorithm for inferring whether closure lifetimes are higher-ranked, I think. The below code compiles fine: #![feature(closure_lifetime_binder)]
fn main() {
let _c = for<'a> |b: &'a u8| -> &'a u8 { b };
}
This is just #34162. |
This issue also appears when using a struct with a lifetime: #![feature(closure_lifetime_binder)]
fn main() {
let _c = |b: S<'_>| -> & () { b.thing() };
}
struct S<'a>(&'a ());
impl<'a> S<'a> {
fn thing(self) -> &'a () {
self.0
}
} And the proposed workaround with closure lifetimes also works. The following workaround (normally) works, even in stable Rust: #![feature(closure_lifetime_binder)]
fn main() {
// ERROR:
// let _c = |b: S<'_>| -> & () { b.thing() };
// WORKAROUND:
let _c = for<'a> |b: S<'a>| -> &'a () { b.thing() };
// However, workaround above isn't always possible
// (1. Requires nightly, 2. closures can't return impl Fn/Traits)
// So instead let's try another workaround by helping out the compiler:
let _c = fix_lifetime(|b: S| b.thing());
let _c = fix_lifetime(for<'a> |b: S<'a>| -> &'a () { b.thing() }); // for demonstration, but this is overkill
}
// Helps the compiler out a little
fn fix_lifetime<F, T>(f: F) -> F
where
F: for<'a> FnOnce(S<'a>) -> &'a T,
{
f
}
struct S<'a>(&'a ());
impl<'a> S<'a> {
fn thing(self) -> &'a () {
self.0
}
} Unfortunately, in my situation, I must be doing something a little too advanced for the compiler to be able to handle and I'm getting a "error: higher-ranked lifetime error" with no further information. Filing a separate issue for that, because it's not as easy to reproduce. |
Closing as duplicate of #58052 which will get fixed once |
@fmease I wouldn’t mind the |
Yeah, it sure feels like that, I agree. Note that as far as I'm aware, type inference algorithms generally work pretty poorly when higher-ranked type-level entities (types, lifetimes, …) are involved because it's hard to design a good algorithm, there are always trade-offs to be made (let me just link to a random paper why not). Of course it would be wonderful if we were to default to inferring higher-ranked lifetimes in the types of closure arguments but that might be backward incompatible or have other unforeseen consequences (maybe the Not being able to write closures with RPIT is also a bummer but I'm pretty sure that this is being discussed as part of the ITE initiative (“impl-Trait everywhere”) and that this restriction might get lifted in the future. Note that you can already use the feature #![feature(type_alias_impl_trait, closure_lifetime_binder)]
fn main() {
type F<'a> = impl FnOnce(&i32) -> (&'a i32, &i32);
let f = for<'a> |x: &'a i32| -> F<'a> { move |y: &i32| (x, y) };
} And if you're already using nightly / CLBs then you could very well also use TAITs (/half serious). Finally, I'd like to clarify that I'm extremely grateful for the work the types team & the lang team is doing and while progress might appear to be slow, there's a lot of development and many discussions happening almost every single day to drive all those features forward. |
@fmease thank you for the thoughtful response! Forgot about TAIT for a minute there. That workaround seems fine to me for now, once it stabilizes. |
This code does not compile:
It did in the past though. Starting in 1.36, it comes with this warning (https://godbolt.org/z/W7KGM3369):
(I do not think there is any chance that this code has UB)
But this code does compile:
At the very least, I think that the diagnostic here is bad. I can't figure out what it is trying to tell me.
This was all re-minimized from an already-minimzed example from @jyn514 :
This is the code we'd really like to see compile.
I'm going to just uh apply all the labels I think are applicable please fix them if they're wrong.
The text was updated successfully, but these errors were encountered: