-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Incomprehensible error message when inference fails for closure #24680
Comments
cc @aturon @nikomatsakis do you think it would be feasible to fix this by the 1.0 release? It's a pretty unfortunate papercut for both iron and hyper. I remember I recently helped @brson with this problem when he was using iron. |
Very similar case based on nickel's usage of hyper: #[allow(dead_code)]
struct Bar<'a, 'b> {
a: &'a (),
b: &'b ()
}
#[allow(dead_code)]
struct Qux<'a> {
a: &'a ()
}
#[allow(dead_code)]
struct Foo<'a> {
a: &'a ()
}
trait Handler {
fn handle<'a, 'k>(&'a self, Bar<'a, 'k>, Qux<'a>) -> Foo<'a>;
}
impl<F> Handler for F where F: for<'a, 'k> Fn(Bar<'a, 'k>, Qux<'a>) -> Foo<'a> + Sync + Send {
fn handle<'a, 'k>(&'a self, req: Bar<'a, 'k>, res: Qux<'a>) -> Foo<'a> {
self(req, res)
}
}
fn call_handler<H: Handler>(h: H) {
println!("call_handler");
h.handle(Bar { a: &(), b: &() }, Qux { a: &() });
}
fn call_closure<F: for<'a, 'k> Fn(Bar<'a, 'k>, Qux<'a>) -> Foo<'a> + Sync + Send>(f: F) {
println!("call_closure");
f(Bar { a: &(), b: &() }, Qux { a: &() });
}
fn wrapped_call_handler<F: for<'a, 'k> Fn(Bar<'a, 'k>, Qux<'a>) -> Foo<'a> + Sync + Send>(f: F) {
println!("wrapped_call_handler");
call_handler(f)
}
fn main() {
// These work
call_closure(|_bar, qux| Foo { a: qux.a });
wrapped_call_handler(|_bar, qux| Foo { a: qux.a });
// These fail
// 'Type must be known'
//call_handler(|_bar, qux| Foo { a: qux.a });
// error: type mismatch resolving `for<'a,'k> <[closure <anon>:52:18: 52:57] as core::ops::FnOnce<(Bar<'a, 'k>, Qux<'a>)>>::Output == Foo<'a>`:
// expected bound lifetime parameter 'a
//call_handler(|_bar: Bar, qux: Qux| Foo { a: qux.a });
} Playpen: http://is.gd/OEkSd4 The fact that it works with a wrapping function means it's possible to get things done with convenience macros, which suggests the compiler is at least able to reason about this at some level. |
Nominating because I hit this quickly trying to use Iron, the error was impenetrable and I had to ask for help. |
Accidentally duped this bug, but not before coming up with a more minimal test case: trait Foo {}
impl<T: Fn(&())> Foo for T {}
fn baz<T: Foo>(_: T) {}
fn main() {
baz(|_| ());
} |
I updated the title to reflect the fact that the error message is really bad here. It'd be nice to improve the inference, but in short term error message is priority. |
P-high : provide better feedback in the error message to guide the user towards adding type annotations on the closure arguments. |
@nikomatsakis Should I open another issue for the example I added? I don't know of any syntax available for type annotating the return type with lifetime requirements other than wrapping with a function? |
@Ryman I'm not sure whether opening a separate issue is necessary, as long as we make sure not to close this one with whatever error message improvements we land to address the P-high part of this. |
I've ran into this with: fn main() {
let head = [(1,2), (3,4)];
let tail = [(4,5), (6,7)];
// missing .cloned()
let _:Vec<_> = head.iter().chain(tail.iter().map(|x|{(x.0+1,x.1+1)})).collect();
}
To Rust's credit "expected tuple, found &-ptr" was a good hint, but the error as a whole—with anon closure and iterator's guts—looks rather scary. |
Just ran into this while using hyper. It's completely incomprehensible and obscure. Is there a general fix to it? |
cc @brson is this roughly the case you were talking about today as well? |
Why does @bstrie's example give a better error message on stable than on beta and nightly? Neither beta nor nightly mention "type X implements Fn(...) but Fn(...) is required" |
I think there are two separable (and important) steps to take here---
|
cc @jonathandturner :) |
@nikomatsakis do you think that #26937 is a duplicate? |
@shepmaster well my feeling is that there are various intersecting problems here. First off, our output is pretty hard to read in general (because we don't do a good job "desugaring" the fn traits and so forth). Second, we don't handle higher-ranked messages very well. Finally, and least likely to be fixed, the inference has some limitations. So probably the answer is "yes", but maybe the right thing is to try and separate out the various problems into distinct issues that are more specific. |
triage: Dropped to P-medium just because the impact is relatively low. |
@brson: I remember a forum thread on the future priorities for Rust, which I couldn't find back now. It referred to the 2016 survey that found that the biggest challenge for Rust adoption in the eyes of the users is the learning curve. I think there is a connection between learnability and how easily developers understand error messages. |
@sanmai-NL - absolutely error messages are an important part of learnability/usability. Here, I think priorities above medium mean that this bug severely impacts the correctness of code or stability of the compiler (crashing the compiler, for example). We're doing on-going work to address error messages holistically (eg #35233 as one example), so as a whole improving errors is a high priority for us, but as far as bug triage goes, individual bugs fall closer to the medium priority when weighed against much worse experiences (like compiler crashes or bad code) |
Yesterday, I answered a question on Stack Overflow about this issue. I tried to come up with an explanation for the error message, in the hope that it would provide some insight on how to fix the issue in the compiler. (I didn't debug the compiler compiling the code below or even read the compiler's source code to validate any of this, so my analysis could be completely wrong!) In case the above link becomes broken in the future, I'm reproducing parts of the question (from Jacob Brown) and of my answer below. The code that triggers the issue is this:
This code raises the following compiler errors:
What seems to happen is that the compiler implements I tried to replicate the error by defining a struct by hand (using unstable features). First, I defined the struct the correct way:
This Then, I broke it:
What I've done here is that I've removed the This fails to compile with the following errors:
The first error is the same, but instead of an internal name like The second error is different but means pretty much the same thing. |
I just hit this again in a new crate, which made me decide to make the generic be |
Closing in favor of #41078. |
Clean up callable type mismatch errors ```rust error[E0593]: closure takes 1 argument but 2 arguments are required here --> ../../src/test/ui/mismatched_types/closure-arg-count.rs:13:15 | 13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); | ^^^^^^^ -------------------------- takes 1 argument | | | expected closure that takes 2 arguments ``` instead of ```rust error[E0281]: type mismatch: the type `[closure@../../src/test/ui/mismatched_types/closure-arg-count.rs:13:23: 13:49]` implements the trait `for<'r> std::ops::FnMut<(&'r {integer},)>`, but the trait `for<'r, 'r> std::ops::FnMut<(&'r {integer}, &'r {integer})>` is required (expected a tuple with 2 elements, found one with 1 elements) --> ../../src/test/ui/mismatched_types/closure-arg-count.rs:13:15 | 13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); | ^^^^^^^ ``` Fix #21857, re #24680.
Gives:
Playpen: http://is.gd/E7sskd
Couldn't tell if this was #16473, @reem thinks it might be different. Either way, this hurts using hyper's server easily:
Server::http(|req, res| {}).listen(8080)
.The text was updated successfully, but these errors were encountered: