Skip to content

diagnostics: "one type is more general" for two identical types? #75791

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
matthiaskrgr opened this issue Aug 21, 2020 · 17 comments
Closed

diagnostics: "one type is more general" for two identical types? #75791

matthiaskrgr opened this issue Aug 21, 2020 · 17 comments
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions C-bug Category: This is a bug. P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@matthiaskrgr
Copy link
Member

While looking through some clippy lint warnings in rust-lang/rust-clippy#5939 I found this very confusing error message:

use std::io::{self};
use std::path::{Path, PathBuf};

pub fn main() {
    let path = &PathBuf::from("a");
    do_op(path, "remove file", std::fs::remove_file); // redundant closure
}

fn do_op<F>(path: &Path, _desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        Err(ref _e) => {}
        Err(_e) => {}
    }
}
error[E0308]: mismatched types
 --> src/main.rs:6:5
  |
6 |     do_op(path, "remove file", std::fs::remove_file); // redundant closure
  |     ^^^^^ one type is more general than the other
  |
  = note: expected type `std::ops::FnOnce<(&std::path::Path,)>`
             found type `std::ops::FnOnce<(&std::path::Path,)>`

note that expected type and found type are identical which is not helpful 😅

This happens on

rustc 1.47.0-nightly (e15510ca3 2020-08-20)
binary: rustc
commit-hash: e15510ca33ea15c893b78710101c962b11459963
commit-date: 2020-08-20
host: x86_64-unknown-linux-gnu
release: 1.47.0-nightly
LLVM version: 10.0

and also on 1.46.0-beta.4.

On stable 1.45.2, the message looks different though:

error[E0631]: type mismatch in function arguments
  --> src/main.rs:6:32
   |
6  |     do_op(path, "remove file", std::fs::remove_file); // redundant closure
   |                                ^^^^^^^^^^^^^^^^^^^^
   |                                |
   |                                expected signature of `for<'r> fn(&'r std::path::Path) -> _`
   |                                found signature of `fn(_) -> _`
...
9  | fn do_op<F>(path: &Path, _desc: &str, mut f: F)
   |    ----- required by a bound in this
10 | where
11 |     F: FnMut(&Path) -> io::Result<()>,
   |        ------------------------------ required by this bound in `do_op`

error[E0271]: type mismatch resolving `for<'r> <fn(_) -> std::result::Result<(), std::io::Error> {std::fs::remove_file::<_>} as std::ops::FnOnce<(&'r std::path::Path,)>>::Output == std::result::Result<(), std::io::Error>`
  --> src/main.rs:6:5
   |
6  |     do_op(path, "remove file", std::fs::remove_file); // redundant closure
   |     ^^^^^ expected bound lifetime parameter, found concrete lifetime
...
9  | fn do_op<F>(path: &Path, _desc: &str, mut f: F)
   |    ----- required by a bound in this
10 | where
11 |     F: FnMut(&Path) -> io::Result<()>,
   |                        -------------- required by this bound in `do_op`
@matthiaskrgr matthiaskrgr added the C-bug Category: This is a bug. label Aug 21, 2020
@matthiaskrgr
Copy link
Member Author

Just for the record, the working code was
do_op(path, "remove file", |f| std::fs::remove_file(f));

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions regression-from-stable-to-beta Performance or correctness regression from stable to beta. labels Aug 21, 2020
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Aug 21, 2020
@estebank
Copy link
Contributor

I'm on the street right now. If someone can identify the nightly the output changed I can track the pr and hopefully see how we can fox it back tomorrow.

@Dylan-DPC-zz
Copy link

Marking this as P-high based on the wg-prioritization discussion

@Dylan-DPC-zz Dylan-DPC-zz added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Aug 25, 2020
@matthiaskrgr
Copy link
Member Author

matthiaskrgr commented Aug 26, 2020

I tried to get cargo-bisect-rustc to work and it seems the regressing merge is 1557fb0
(I hope I used the tool correctly... 😅 )

@nikomatsakis
Copy link
Contributor

This is almost certainly due to #72493. The error seems legit, as discussed here. The error message is quite misleading, what's really happening is that the type of std::fs::remove_file doesn't implement for<'a> FnMut(&'a Path) but just FnMut(&'b Path) for some 'b. We have some specializd diagnostic paths to try and express this more clearly but they are not triggering here for reasons I'm not entirely sure of.

@pnkfelix
Copy link
Member

pnkfelix commented Sep 3, 2020

discussed in T-compiler meeting. Assigning to @estebank to see if they can make progress on it over next week. Also nominating to ensure we circle back around to it next week if progress isn't made

@spastorino
Copy link
Member

Is this one a stable regression now?, also is it the same as #74400 ?

@lqd
Copy link
Member

lqd commented Sep 3, 2020

yes that's on stable now

@lqd
Copy link
Member

lqd commented Sep 3, 2020

and to answer the question: both are indeed duplicates of each other, they are higher-ranked subtype errors involving placeholder regions from the same universe. NLL's nice region error reporting code doesn't kick in because it handles TraitRefs while these are PolyTraitRefs.

@estebank
Copy link
Contributor

estebank commented Sep 4, 2020

I can get the following output:

error: implementation of `std::ops::FnOnce` is not general enough
   --> fil3.rs:6:5
    |
6   |       do_op(path, "remove file", std::fs::remove_file); // redundant closure
    |       ^^^^^ doesn't satisfy where-clause
    |
   ::: /Users/ekuber/workspace/rust/library/core/src/ops/function.rs:219:1
    |
219 | / pub trait FnOnce<Args> {
220 | |     /// The returned type after the call operator is used.
221 | |     #[lang = "fn_once_output"]
222 | |     #[stable(feature = "fn_once_output", since = "1.12.0")]
...   |
227 | |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
228 | | }
    | |_- trait `std::ops::FnOnce` defined here
    |
note: due to this where-clause on `do_op`...
   --> fil3.rs:11:24
    |
11  |     F: FnMut(&Path) -> io::Result<()>,
    |                        ^^^^^^^^^^^^^^
    = note: ...`std::ops::FnOnce<(&'1 std::path::Path,)>` would have to be implemented for the type `fn(&std::path::Path) -> std::result::Result<(), std::io::Error> {std::fs::remove_file::<&std::path::Path>}`, for any lifetime `'1`...
    = note: ...but `std::ops::FnOnce<(&'2 std::path::Path,)>` is actually implemented for the type `fn(&'2 std::path::Path) -> std::result::Result<(), std::io::Error> {std::fs::remove_file::<&'2 std::path::Path>}`, for some specific lifetime `'2`

But I feel it is not yet ideal.

@lqd
Copy link
Member

lqd commented Sep 4, 2020

Is there enough information at this point of type-checking to output either previous errors (or both ? the E0631 seems more user-friendly, but these spans look more like the previous E0271), so that even if the message doesn't improve it at least doesn't regress anymore ?

Maybe having the previous signatures would be clearer ?

expected signature of `for<'r> fn(&'r std::path::Path) -> _`
   |                                found signature of `fn(_) -> _`

I wonder how we should explain these kinds of errors, maybe linking to closures/Fn* documentation, suggesting wrapping in a closure (but that doesn't always work). Maybe those suggestions are also too tailored to these 2 specific issues but higher-ranked subtyping errors could be arbitrarily complicated.

@spastorino
Copy link
Member

Adding T-compiler label so this can be picked up by our automated prioritization tool and added to the following T-compiler weekly meeting agenda.

@spastorino spastorino added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed regression-from-stable-to-beta Performance or correctness regression from stable to beta. labels Sep 9, 2020
@spastorino
Copy link
Member

As noted this is a stable regression already, adjusting labels accordingly.

@spastorino
Copy link
Member

@solson
Copy link
Member

solson commented Oct 30, 2020

I hope this is the right place for this — it seems like all relevant issues are getting closed as duplicates of this one. For reference, here is more minimal reproduction of the problem, from @khyperia:

fn thing(x: impl FnOnce(&u32)) {}

fn main() {
    let f = |_| ();
    thing(f);
}

Playground link

It can be worked around like this:

fn thing(x: impl FnOnce(&u32)) {}

fn main() {
    let f = |_: &_| ();
    thing(f);
}

@estebank
Copy link
Contributor

Current output:

error: implementation of `FnOnce` is not general enough
 --> src/main.rs:6:5
  |
6 |     do_op(path, "remove file", std::fs::remove_file); // redundant closure
  |     ^^^^^ implementation of `FnOnce` is not general enough
  |
  = note: `fn(&'2 Path) -> Result<(), std::io::Error> {remove_file::<&'2 Path>}` must implement `FnOnce<(&'1 Path,)>`, for any lifetime `'1`...
  = note: ...but it actually implements `FnOnce<(&'2 Path,)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
 --> src/main.rs:5:5
  |
5 |     thing(f);
  |     ^^^^^ implementation of `FnOnce` is not general enough
  |
  = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`...
  = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2`

I think this might be a duplicate of #71723

@jackh726
Copy link
Member

jackh726 commented Feb 3, 2022

Closing as a duplicate of #71723

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: Lifetimes / regions C-bug Category: This is a bug. P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. 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