6

With nightly rust:

Playground

struct Foo<T, F: Fn(&T, &T) -> T> {
    value: T,
    func: F
}

fn main() {
    let lambda = |&x, &y| x + y;
    let foo = Foo {
        value: 5 as i32,
        func: lambda
    };
}

Error message:

Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:8:15
  |
8 |     let foo = Foo {
  |               ^^^ one type is more general than the other
  |
  = note: expected type `std::ops::FnOnce<(&i32, &i32)>`
             found type `std::ops::FnOnce<(&i32, &i32)>`

Note that the expected type and found type are character for character identical. Why is the error message saying that one type is more general than the other, while also saying that they are the same type?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Jeremy Salwen
  • 8,061
  • 5
  • 50
  • 73
  • `5 as i32` -> `5i32` – hellow Jan 24 '19 at 07:46
  • https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=0e1f561f9ab14f7fea49200a8c319bcc, there are not the same. as error message said, "one type is more general than the other" – Stargateur Jan 24 '19 at 07:49
  • Possible duplicate of [In Rust how do you pass a function as a parameter?](https://stackoverflow.com/questions/36390665/in-rust-how-do-you-pass-a-function-as-a-parameter) – hellow Jan 24 '19 at 07:50
  • 1
    The error message says one is more general than the other, but as I mentioned in the question "the expected type and found type are character for character identical" – Jeremy Salwen Jan 24 '19 at 07:56
  • This is not a duplicate of that question (although it may look that way if you read through this question quickly). The question is why is the error printing two types that are exactly the same, and then printing an error that they are different. I have edited the question to make this more clear. – Jeremy Salwen Jan 24 '19 at 08:02
  • I get very different errors on the playground: "found signature of `fn(&_, &_) -> _`, expected signature of `for<'r, 's> fn(&'r i32, &'s i32) -> _`" – Sebastian Redl Jan 24 '19 at 08:12
  • @SebastianRedl Hmm, I can reproduce that error message if I switch to stable Rust. Are you sure you selected Nightly? – Jeremy Salwen Jan 24 '19 at 08:15
  • 1
    @JeremySalwen On Nightly I get the bad error message. But I suspect that the underlying issue is the same. Sounds bug-report-worthy. – Sebastian Redl Jan 24 '19 at 08:22
  • 1
    This is similar (but not a duplicate) of this question from yesterday: https://stackoverflow.com/questions/54329200/mysterious-lifetime-issue-while-implementing-trait-for-dyn-object. The takeaway from that is that the answer is almost certainly related to lifetimes. – Peter Hall Jan 24 '19 at 09:47

1 Answers1

3

With nightly rust:

This appears to be just a "bad" error message in a nightly build. In Rust 1.32 (stable), the errors tell you that this is a lifetime mismatch:

error[E0631]: type mismatch in closure arguments
 --> src/main.rs:8:15
  |
7 |     let lambda = |&x, &y| x + y;
  |                  -------------- found signature of `fn(&_, &_) -> _`
8 |     let foo = Foo {
  |               ^^^ expected signature of `for<'r, 's> fn(&'r i32, &'s i32) -> _`
  |
note: required by `Foo`
 --> src/main.rs:1:1
  |
1 | struct Foo<T, F: Fn(&T, &T) -> T> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `for<'r, 's> <[closure@src/main.rs:7:18: 7:32] as std::ops::FnOnce<(&'r i32, &'s i32)>>::Output == i32`
 --> src/main.rs:8:15
  |
8 |     let foo = Foo {
  |               ^^^ expected bound lifetime parameter, found concrete lifetime
  |
note: required by `Foo`
 --> src/main.rs:1:1
  |
1 | struct Foo<T, F: Fn(&T, &T) -> T> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Why is the error message saying that one type is more general than the other, while also saying that they are the same type?

The types differ only in lifetimes. The nightly message doesn't include lifetimes — perhaps in an attempt to reduce noise in cases where the lifetimes are not relevant. Obviously this is not at all helpful when lifetimes are the only difference between the types.

Consider reporting a bug to the Rust team.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • Is there a tool possibly a `cargo` subcommand that "expands" the code so that all lifetimes are explicitly annotated? – phimuemue Jan 24 '19 at 10:34
  • @phimuemue I haven't seen anything like that, but it could certainly be useful. – Peter Hall Jan 24 '19 at 11:10
  • 1
    @PeterHall, [If input types to closure are specified](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4b3ab7e0f88bf49de4d7eb6d5fbedd12) it works. I'm not sure why! – vikram2784 Jan 24 '19 at 13:16
  • 2
    @VikramFugro It works because you have told the compiler that `T` is `i32`, a type not containing references, so `T: 'static`. – Peter Hall Jan 24 '19 at 13:24
  • Isn't the message `expected signature of for<'r, 's> fn(&'r {integer}, &'s {integer}) -> _`, a bit confusing? It means the compiler knows `T`'s type – vikram2784 Jan 24 '19 at 13:41