-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Description
If I have a method that takes a generic parameter constrained by a trait, and the trait is implemented for F: for<'a> FnOnce(Foo<'a>) -> Bar<'a>1, then calling the method with a closure expression fails to infer the higher-ranked lifetime and produces a confusing error.
Given the following code: (play.rust-lang.org)
use std::marker::PhantomData;
struct Value<'a> {
_marker: PhantomData<&'a ()>,
}
impl<'a> Value<'a> {
fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
trait Callable {
fn call<'a>(self, s: Value<'a>) -> Value<'a>;
}
impl<F> Callable for F
where
F: for<'a> FnOnce(Value<'a>) -> Value<'a>,
{
fn call<'a>(self, s: Value<'a>) -> Value<'a> {
self(s)
}
}
fn take_callable<C: Callable>(_: C) {}
fn main() {
take_callable(|v: Value| Value::new());
}The current output is:
error[E0308]: mismatched types
--> src/main.rs:28:5
|
28 | take_callable(|v: Value| Value::new());
| ^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected struct `Value<'_>`
found struct `Value<'a>`
note: the lifetime requirement is introduced here
--> src/main.rs:25:21
|
25 | fn take_callable<C: Callable>(_: C) {}
| ^^^^^^^^
For more information about this error, try `rustc --explain E0308`.
This error does not mention higher-ranked lifetimes, does not explain where the 'a came from or the '_ (and if I use a type like &str instead of Value then it doesn't even print the '_ lifetime), flips the "expected" and "found" types, points at the C: Callable bound as the lifetime requirement despite no lifetime being visible on that bound, and does not even highlight the closure expression's span. If I modify the code to return v instead of a Value<'static> then it does add the following note:
note: the anonymous lifetime #1 defined here doesn't meet the lifetime requirements
--> src/main.rs:28:19
|
28 | take_callable(|v: Value| v);
| ^^^^^^^^^^^^
This is a slight improvement but is still confusing.
This is especially confusing as having a method that is bounded by FnOnce directly avoids this error, which I'm told is a special-case in the compiler for inferring higher-ranked lifetimes on closure expressions.
My expectation here is the error should mention higher-ranked lifetimes somehow, preferably both specifying for<'a> Value<'a> and including a note that explains that closure expressions do not infer higher-ranked lifetimes when the generic bound does not specify the higher-ranked lifetime directly.
Footnotes
-
Foo<'a>andBar<'a>may also be&'a T. ↩