Open GregAC opened 3 years ago
I suspect what's happening is the first closures don't capture from the environment so are seen as function pointers both with type fn(i32) -> i32. So this is just an issue of clarifying the second error message e.g. 'no two closure which capture the environment, even if identical, have the same type'.
I think your analysis here is mostly right. The thing is it's actually true that no two closures have the same type, even if they don't capture their environment. What's happening is that closure-to-fn coersion is taking place in the first example — they do have different types, but are coerced to a common type.
So, I'm not sure how to fix the diagnostic, since it's not wrong, it just looks wrong whereas your suggestion is more wrong, even though it appears to match the behavior... The behavior is just unintuitive...
(Sadly, I don't think the rules by which this happens are very well specified — I believe it's less specified than Deref or Unsizing coersion, but maybe I'm just unaware of were the docs are).
I guess it depends how verbose you allow the diagnostics to become an extra
note: two closures can be coerced to the same fn type under certain circumstances, this was not possible here
or similar could work?
I think it would be useful to suggest coercing both closures to a function pointer if possible, but I don't think the diagnostic needs to mention function pointers if coercing isn't possible. Diagnostics should only give you as much info as you need to fix the problem.
I recently learned this is possible and I also wish rustc had taught me this sooner. I think it should say something like:
help: consider using inputs instead of captured variables
| |x, y| x + y
+++
Similar to above
fn main() {
let haa = if true {
Some(|x:u32| x + 1)
} else {
Some(|x:u32| x + 2)
};
}
this throws error as if and else have incompatible types
.
But this compiles fine
fn main() {
let haa = if true {
|x: u32| x + 1
} else {
|x: u32| x + 2
};
}
Consider the following function which returns a closure
impl
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5d676e682519cae13533bd1d5c82ebd3
This builds and runs providing the following output:
This seems reasonable at first glance, however consider a changed version:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=43bdb248873d31bc470b0fc9fb8a2ab3
This fails to build with:
The first example uses two closures and compiles and runs fine, demonstrating we do have two closures of the same type which the output from the second example states cannot happen.
I suspect what's happening is the first closures don't capture from the environment so are seen as function pointers both with type
fn(i32) -> i32
. So this is just an issue of clarifying the second error message e.g. 'no two closure which capture the environment, even if identical, have the same type'.Changing the first example as follows seems to confirm this:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c628f6a790b886b7975542a7fd89f734
(Builds and runs with identical results to the first example)
From reading the rust reference you could say 'closure' inherently means environment capture (i.e.
|x| x + 1
is not a closure), but that conflicts with language used in the rust book so could lead to confusion.If it's intended that closures from the first example should have different types there's something more serious going on with the type inference/checking.
rustc --version --verbose
: