Skip to content
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

Generic Fn wrapper breaks without type annotations #37464

Open
hban opened this issue Oct 29, 2016 · 5 comments
Open

Generic Fn wrapper breaks without type annotations #37464

hban opened this issue Oct 29, 2016 · 5 comments
Labels
A-closures Area: closures (`|args| { .. }`) A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@hban
Copy link

hban commented Oct 29, 2016

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| {}));
}

Run in playground.

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.

@bluss
Copy link
Member

bluss commented Oct 29, 2016

I think that if you add where F: FnOnce(&i32) to the struct definition itself, it helps.

@hban
Copy link
Author

hban commented Oct 29, 2016

It does indeed, but it looks like (another) workaround to me. Since apply function parameter has a trait bound, the constraint on just trait implementation should be enough for the compiler, I think.

@bluss
Copy link
Member

bluss commented Oct 29, 2016

Yes, this is a major annoyance. #35714 is almost the same issue.

@bluss bluss added the A-closures Area: closures (`|args| { .. }`) label Oct 29, 2016
@Mark-Simulacrum Mark-Simulacrum added A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Jul 26, 2017
@steveklabnik
Copy link
Member

Triage: no change

@jonas-schievink jonas-schievink added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label May 7, 2020
@Dylan-DPC
Copy link
Member

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 errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: closures (`|args| { .. }`) A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants