Skip to content

Closure seemingly both implements and doesn't implement a trait #79187

Open
@alexcrichton

Description

@alexcrichton

This is a bit of an odd issue that I ran into today, and one that I think is a bug in rustc but I'm not 100% certain. Given this code:

trait Foo {}

impl<F> Foo for F where F: Fn(&i32) -> &i32 {}

fn take_foo(_: impl Foo) {}

fn main() {
    // Does not compile
    // take_foo(|a| a);
    // take_foo(|a: &i32| a);
    take_foo(|a: &i32| -> &i32 { a });

    // Does compile
    take_foo(identity(|a| a));
    take_foo(identity(|a: &i32| a));
    take_foo(identity(|a: &i32| -> &i32 { a }));

    fn identity<F>(t: F) -> F
    where
        F: Fn(&i32) -> &i32,
    {
        t
    }
}

this fails to compile with:

error[E0308]: mismatched types
  --> src/main.rs:11:5
   |
11 |     take_foo(|a: &i32| -> &i32 { a });
   |     ^^^^^^^^ one type is more general than the other
   |
   = note: expected reference `&i32`
              found reference `&i32`

error: aborting due to previous error

The perplexing part to me is that both calls to take_foo seem pretty equivalent, but the second compiles while the first does not. I've managed to get a variety of error messages trying to reduce this, the original project had a much more opaque "the trait bound is not satisfied" error. It may be the case though that the fix for the above snippet is the fix for the original snippet too though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions