Generic Fn wrapper breaks without type annotations
I have a generic FnWrapper struct for closures that take a &i32 as their only parameter, and a generic apply function that consumes such wrappers (not directly, but via Foo trait).
trait Foo {
fn foo(self, value: &i32);
}
struct FnWrapper<F>(F);
impl<F: FnOnce(&i32)> Foo for FnWrapper<F> {
fn foo(self, value: &i32) {
(self.0)(value);
}
}
fn apply<F: Foo>(_: F) {}
fn main() {
// Error.
apply(FnWrapper(|_| {}));
// Ok with type annotations.
apply(FnWrapper(|_: &i32| {}));
}
When invoking apply without any annotations, compiler complains about:
error[E0271]: type mismatch resolving `for<'r> <[closure@<anon>:17:21: 17:27] as std::ops::FnOnce<(&'r i32,)>>::Output == ()`
--> <anon>:17:5
|
17 | apply(FnWrapper(|_| {}));
| ^^^^^ expected bound lifetime parameter , found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#0r
= note: required because of the requirements on the impl of `Foo` for `FnWrapper<[closure@<anon>:17:21: 17:27]>`
= note: required by `apply`
error[E0281]: type mismatch: the type `[closure@<anon>:17:21: 17:27]` implements the trait `std::ops::FnOnce<(_,)>`, but the trait `for<'r> std::ops::FnOnce<(&'r i32,)>` is required (expected concrete lifetime, found bound lifetime parameter )
--> <anon>:17:5
|
17 | apply(FnWrapper(|_| {}));
| ^^^^^
|
= note: required because of the requirements on the impl of `Foo` for `FnWrapper<[closure@<anon>:17:21: 17:27]>`
= note: required by `apply`
Simply adding type annotation to the closure parameter will make this compile, so it looks like a bug to me.
I think that if you add
where F: FnOnce(&i32)to the struct definition itself, it helps.bluss at 2016-10-29 09:47:22
It does indeed, but it looks like (another) workaround to me. Since
applyfunction parameter has a trait bound, the constraint on just trait implementation should be enough for the compiler, I think.hban at 2016-10-29 09:55:49
Yes, this is a major annoyance. #35714 is almost the same issue.
bluss at 2016-10-29 10:05:37
Triage: no change
Steve Klabnik at 2020-05-07 12:29:12
Current output:
error: implementation of `FnOnce` is not general enough --> src/main.rs:17:5 | 17 | apply(FnWrapper(|_| {})); | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'2 i32)` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2` error[[E0308]](https://doc.rust-lang.org/nightly/error_codes/E0308.html): mismatched types --> src/main.rs:17:5 | 17 | apply(FnWrapper(|_| {})); | ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected trait `for<'a> FnOnce<(&'a i32,)>` found trait `FnOnce<(&i32,)>` note: this closure does not fulfill the lifetime requirements --> src/main.rs:17:21 | 17 | apply(FnWrapper(|_| {})); | ^^^ note: the lifetime requirement is introduced here --> src/main.rs:13:13 | 13 | fn apply<F: Foo>(_: F) {} | ^^^ help: consider specifying the type of the closure parameters | 17 | apply(FnWrapper(|_: &_| {})); | ~~~~~~~ For more information about this error, try `rustc --explain E0308`. error: could not compile `playground` (bin "playground") due to 2 previous errorsDylan DPC at 2023-06-02 09:19:04