-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Clarification of compiler diagnostic 'no two closures, even if identical, have the same type' #87961
Comments
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
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:
|
Similar to above fn main() {
let haa = if true {
Some(|x:u32| x + 1)
} else {
Some(|x:u32| x + 2)
};
} this throws error as 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
:The text was updated successfully, but these errors were encountered: