Skip to content

Self-contradictory error message about Fn types on beta/nightly #57875

Open
@jeremysalwen

Description

@jeremysalwen

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=e973951415f5092af183ea13d11177cf

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

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

See also https://stackoverflow.com/questions/54341465/rust-expected-type-error-prints-mismatched-types-that-are-exactly-the-same?noredirect=1

Activity

estebank

estebank commented on Jan 24, 2019

@estebank
Contributor

This is a diagnostics regression given the current stable output (even though it wasn't that good to begin with):

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> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

but needs consideration on wether the code as written should be accepted instead. Why are we evaluating to FnOnce in the first place? Note that changing F to FnMut doesn't change the types reported.

CC @rust-lang/lang

ExpHP

ExpHP commented on Jan 24, 2019

@ExpHP
Contributor

Why are we evaluating to FnOnce in the first place?

Is it not just showing FnOnce because the associated type is defined on FnOnce? This isn't related to the fact that it does not compile.

ExpHP

ExpHP commented on Jan 24, 2019

@ExpHP
Contributor

The workaround is to annotate the closure parameter types so that they get assigned higher-ranked regions or whatever you call them.

let lambda = |&x: &_, &y: &_| x + y;

This is a well-known problem that has hit many a rustacean. But I thought the error messages used to be more descriptive, saying mething about "concrete" versus "bound" lifetimes. Even if it was terribly confusing language, it was at least something the user could Google.

lqd

lqd commented on Jan 27, 2019

@lqd
Member

This issue is very similar to #57362 on which I have been working (same RegionResolutionError: a SubSupConflict with two placeholder regions and Subtype region origins — but in this case the expected/found values are PolyTraitRefs instead of TraitRefs, bypassing the nice_region_errors into this "mismatched types" fallback which doesn't show the self tys) and I hope to look into this one next.

added
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Jan 28, 2019
added
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
on Jun 11, 2020
kadiwa4

kadiwa4 commented on Feb 26, 2023

@kadiwa4
Contributor

Current output (rustc 2023-02-25):

error[E0308]: mismatched types
  --> src/main.rs:8:15
   |
8  |       let foo = Foo {
   |  _______________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ one type is more general than the other
   |
   = note: expected trait `for<'a, 'b> Fn<(&'a i32, &'b i32)>`
              found trait `Fn<(&i32, &i32)>`
note: this closure does not fulfill the lifetime requirements
  --> src/main.rs:7:18
   |
7  |     let lambda = |&x, &y| x + y;
   |                  ^^^^^^^^
note: the lifetime requirement is introduced here
  --> src/main.rs:1:18
   |
1  | struct Foo<T, F: Fn(&T, &T) -> T> {
   |                  ^^^^^^^^^^^^^^^

error: implementation of `FnOnce` is not general enough
  --> src/main.rs:8:15
   |
8  |       let foo = Foo {
   |  _______________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&'2 i32, &i32) -> i32` must implement `FnOnce<(&'1 i32, &i32)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&'2 i32, &i32)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
  --> src/main.rs:8:15
   |
8  |       let foo = Foo {
   |  _______________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&i32, &'2 i32) -> i32` must implement `FnOnce<(&i32, &'1 i32)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&i32, &'2 i32)>`, for some specific lifetime `'2`

very long, but the problem is made clear

estebank

estebank commented on Mar 4, 2023

@estebank
Contributor

Really happy to see progress on this front! The last two errors should not be emitted (as they are redundant), but at the very least it should be only one, so I'll leave the ticket open, but I'm ok with the current output as is.

RodBurman

RodBurman commented on Dec 19, 2024

@RodBurman

I think the errors emitted have got worse again, as compiling with:

cargo -V -v
cargo 1.83.0 (5ffbef321 2024-10-29)
release: 1.83.0
commit-hash: 5ffbef3211a8c378857905775a15c5b32a174d3b
commit-date: 2024-10-29
host: aarch64-apple-darwin
libgit2: 1.8.1 (sys:0.19.0 vendored)
libcurl: 8.7.1 (sys:0.4.74+curl-8.9.0 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: Mac OS 15.2.0 [64-bit]

Produces:

Compiling fooilambda v0.1.0 (/Users/rod/code/rust/triage/fooilambda)
error: implementation of `Fn` is not general enough
  --> src/main.rs:8:16
   |
8  |       let _foo = Foo {
   |  ________________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ implementation of `Fn` is not general enough
   |
   = note: closure with signature `fn(&'2 i32, &i32) -> i32` must implement `Fn<(&'1 i32, &i32)>`, for any lifetime `'1`...
   = note: ...but it actually implements `Fn<(&'2 i32, &i32)>`, for some specific lifetime `'2`

error: implementation of `Fn` is not general enough
  --> src/main.rs:8:16
   |
8  |       let _foo = Foo {
   |  ________________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ implementation of `Fn` is not general enough
   |
   = note: closure with signature `fn(&i32, &'2 i32) -> i32` must implement `Fn<(&i32, &'1 i32)>`, for any lifetime `'1`...
   = note: ...but it actually implements `Fn<(&i32, &'2 i32)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
  --> src/main.rs:8:16
   |
8  |       let _foo = Foo {
   |  ________________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&'2 i32, &i32) -> i32` must implement `FnOnce<(&'1 i32, &i32)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&'2 i32, &i32)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
  --> src/main.rs:8:16
   |
8  |       let _foo = Foo {
   |  ________________^
9  | |         value: 5 as i32,
10 | |         func: lambda
11 | |     };
   | |_____^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&i32, &'2 i32) -> i32` must implement `FnOnce<(&i32, &'1 i32)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&i32, &'2 i32)>`, for some specific lifetime `'2`

error: could not compile `fooilambda` (bin "fooilambda") due to 4 previous errors
```
for the example code (though I did change foo to _foo to remove the unused item warning). Note duplicate errors for Fn and FnOnce and the helpful text about the closure is no longer produced.
added
T-typesRelevant to the types team, which will review and decide on the PR/issue.
on Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsA-type-systemArea: Type systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types 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

        Participants

        @lqd@jeremysalwen@crlf0710@Centril@ExpHP

        Issue actions

          Self-contradictory error message about Fn types on beta/nightly · Issue #57875 · rust-lang/rust