Skip to content

for<'a> Fn(<A as B<'a>>::C) fails incosistently and requires unnecessary type annotations #90875

Closed

Description

I tried this code:

trait Variable<'a> {
    type Type;
}

impl Variable<'_> for () {
    type Type = ();
}

fn check<F, T>(_: F)
where
    F: Fn(T), // <- if removed, all fn_* then require type annotations
    F: for<'a> Fn(<T as Variable<'a>>::Type),
    T: for<'a> Variable<'a>,
{
}

fn test(arg: impl Fn(())) {
    fn fn_1(_: ()) {}
    let fn_2 = |_: ()| ();
    let fn_3 = |a| fn_1(a);
    let fn_4 = arg;

    check(fn_1); // Error
    check(fn_2); // Ok
    check(fn_3); // Ok
    check(fn_4); // Error
    check::<_, ()>(fn_1); // Ok
    check::<_, ()>(fn_4); // Ok
}

(playground)

I expected to see this happen: the code compiles fine.

Instead, this happened: check(fn_1) and check(fn_4) fails to type check, and although the error message is not related to type inference, annotating the type parameter T fixes the problem. the same thing happens when removing the bound F: Fn(T), but then for all check(fn_*).

Seems to be related to #79207. cc @jackh726

Error message

   Compiling playground v0.0.1 (/playground)
error[E0631]: type mismatch in function arguments
  --> src/lib.rs:23:11
   |
18 |     fn fn_1(_: ()) {}
   |     -------------- found signature of `fn(()) -> _`
...
23 |     check(fn_1); // Error
   |     ----- ^^^^ expected signature of `for<'a> fn(<() as Variable<'a>>::Type) -> _`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `check`
  --> src/lib.rs:12:8
   |
9  | fn check<F, T>(_: F)
   |    ----- required by a bound in this
...
12 |     F: for<'a> Fn(<T as Variable<'a>>::Type),
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`

error[E0277]: expected a `Fn<(<() as Variable<'a>>::Type,)>` closure, found `impl Fn(())`
  --> src/lib.rs:26:11
   |
26 |     check(fn_4); // Error
   |     ----- ^^^^ expected an `Fn<(<() as Variable<'a>>::Type,)>` closure, found `impl Fn(())`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `check`
  --> src/lib.rs:12:8
   |
9  | fn check<F, T>(_: F)
   |    ----- required by a bound in this
...
12 |     F: for<'a> Fn(<T as Variable<'a>>::Type),
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
help: consider further restricting this bound
   |
17 | fn test(arg: impl Fn(()) + for<'a> std::ops::Fn<(<() as Variable<'a>>::Type,)>) {
   |                          +++++++++++++++++++++++++++++++++++++++++++++++++++++

Some errors have detailed explanations: E0277, E0631.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground` due to 2 previous errors

Context

Original thread in users forum

Meta

Tested on stable and nightly branches of playground:

  • Stable version: 1.56.1
  • Nightly version: 1.58.0-nightly (2021-11-09 8b09ba6)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-inferenceArea: Type inferenceA-lifetimesArea: Lifetimes / regionsA-traitsArea: Trait systemA-typesystemArea: The type systemC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions