Open elichai opened 3 years ago
The output in beta is
error: implementation of `FnOnce` is not general enough
--> src/main.rs:7:5
|
7 | serialize_wrap(serialize, &Test);
| ^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 Test) {serialize::<&'2 Test>}` must implement `FnOnce<(&'1 Test,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 Test,)>`, for some specific lifetime `'2`
You can make this compile by adding a named lifetime tying f
and ser
, but that might not be what you want to do, depending on the specifics.
@estebank, Thanks for responding.
your fix allows me to understand the problem, if I got it correctly it means that:
The compiler assumes that the &Test
input to serialize_wrap and the &Test
input to FnOnce have different lifetimes.
by introducing a named lifetime we tell it that they need to have the same lifetime.
The new diagnostic is obviously better but I also don't think I fully understand it to be honest.
The diagnostic absolutely needs to be improved. The reason this doesn't compile is because the signature desugars to fn serialize_wrap<'b, F: for<'a> FnOnce(&'a Test)>(f: F, ser: &'b Test)
.
And that is a problem because the compiler can't ensure that 'b
will live when F
gets called.
Here's an even simpler one:
fn check<S: AsRef<str>>(_: S) -> bool {
false
}
fn main() {
let options: Vec<String> = Vec::new();
let _ = options.into_iter().filter(check::<&String>);
}
On stable this produces the unhelpful
error[E0308]: mismatched types
--> src/main.rs:7:33
|
7 | let _ = options.into_iter().filter(check::<&String>);
| ^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&String,)>`
found type `FnOnce<(&String,)>`
On beta/nightly it's a little better, but still pretty inscrutable:
error: implementation of `FnOnce` is not general enough
--> src/main.rs:7:33
|
7 | let _ = options.into_iter().filter(check::<&String>);
| ^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 String) -> bool {check::<&'2 String>}` must implement `FnOnce<(&'1 String,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 String,)>`, for some specific lifetime `'2`
In this particular case it can be fixed with:
fn check<S: AsRef<str>>(_: &S) -> bool {
false
}
fn main() {
let options: Vec<String> = Vec::new();
let _ = options.into_iter().filter(check::<String>);
}
But that's not really a general solution. Just sharing in case others run into something similar and ends up here.
Current output:
error[[E0308]](https://doc.rust-lang.org/nightly/error_codes/E0308.html): mismatched types
--> src/main.rs:8:5
|
8 | serialize_wrap(serialize, &Test);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'a> FnOnce<(&'a Test,)>`
found trait `FnOnce<(&Test,)>`
note: the lifetime requirement is introduced here
--> src/main.rs:11:22
|
11 | fn serialize_wrap<F: FnOnce(&Test)>(f: F, ser: &Test) {
| ^^^^^^^^^^^^^
error: implementation of `FnOnce` is not general enough
--> src/main.rs:8:5
|
8 | serialize_wrap(serialize, &Test);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 Test) {serialize::<&'2 Test>}` must implement `FnOnce<(&'1 Test,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 Test,)>`, for some specific lifetime `'2`
error[[E0308]](https://doc.rust-lang.org/nightly/error_codes/E0308.html): mismatched types
--> src/main.rs:7:13
|
7 | let _ = options.into_iter().filter(check::<&String>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'a> FnMut<(&'a String,)>`
found trait `FnMut<(&String,)>`
note: the lifetime requirement is introduced here
--> /rustc/065a1f5df9c2f1d93269e4d25a2acabbddb0db8d/library/core/src/iter/traits/iterator.rs:925:12
error: implementation of `FnOnce` is not general enough
--> src/main.rs:7:13
|
7 | let _ = options.into_iter().filter(check::<&String>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 String) -> bool {check::<&'2 String>}` must implement `FnOnce<(&'1 String,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 String,)>`, for some specific lifetime `'2`
https://play.rust-lang.org/?gist=d912ef0e107be493dd10b72f973897ba
The current output is:
I'm not quite sure what's the right diagnostic here, maybe that it should be by value?