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

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

Open
jeremysalwen opened this issue Jan 24, 2019 · 6 comments
Open

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

jeremysalwen opened this issue Jan 24, 2019 · 6 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-type-system Area: Type system 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

@jeremysalwen
Copy link

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

@Centril Centril added A-type-system Area: Type system A-diagnostics Area: Messages for errors, warnings, and lints labels Jan 24, 2019
@estebank estebank added A-lifetimes Area: Lifetimes / regions regression-from-stable-to-beta Performance or correctness regression from stable to beta. labels Jan 24, 2019
@estebank
Copy link
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

@estebank estebank removed the regression-from-stable-to-beta Performance or correctness regression from stable to beta. label Jan 24, 2019
@ExpHP
Copy link
Contributor

ExpHP commented Jan 24, 2019

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
Copy link
Contributor

ExpHP commented Jan 24, 2019

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
Copy link
Member

lqd commented Jan 27, 2019

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.

@jonas-schievink jonas-schievink added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jan 28, 2019
@crlf0710 crlf0710 added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jun 11, 2020
@kadiwa4
Copy link
Contributor

kadiwa4 commented Feb 26, 2023

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
Copy link
Contributor

estebank commented Mar 4, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions A-type-system Area: Type system 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

8 participants