-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Improve error message for uninferrable types #38812 #39361
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @arielb1 (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
cc @dherman @jonathandturner @estebank -- any tips on wording much appreciated. One thing we weren't sure about was whether we could find a good way to integrate the "partial type" information that we have. For example, we we know that the variable |
"unable to fully infer type(s)"); | ||
|
||
err.note("type annotations or generic parameter binding required"); | ||
err.span_label(cause.span, &format!("cannot infer type")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep the old message here:
err.span_label(span, &format!("cannot infer type for `{}`", name));
In particular, the name
is useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
let mut err = struct_span_err!(self.tcx.sess, | ||
cause.span, | ||
E0282, | ||
"unable to fully infer type(s)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but I do prefer this message being short and snappy :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be nice if we could check how many types couldn't be fully inferred and provide the appropriate text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some possible things we could say:
- "unable to fully infer types" -- I don't think the (s) is needed. There are always lots of types at play, a plural is always appropriate. =)
- "type annotations needed"
- "multiple possible types detected; annotations needed to clarify" -- or something like that?
- I'd like to get across that rustc is refusing to guess what your program means, basically, by picking a random type on your behalf.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "type annotations needed" is the best of the three. IMHO it's better to tell me what to fix so that I can more quickly take the action to fix the error.
| ^^^^^^ cannot infer type for `T` | ||
| - ^^^^^^ cannot infer type | ||
| | | ||
| annotating the type for the variable `x` would help |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a similar test, but for the case where the thing being assigned is a more complex pattern?
Something like this:
let (x,) = (vec![],);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Hmm also this "note: type annotations or generic parameter binding required" feels a bit superfluous. I wonder where that comes from. |
I feel the output would be slightly more helpful with something along the lines of:
Thoughts? |
Cool idea! I definitely like this approach. It seems like we'll need to just pick the right place to annotate. Sometimes we'll have the variable decl to annotate, but other times we'll have to expression. As @estebank points out there's a bit of decision on which to choose, but I think we could come up with a heuristic that can just pick one of the choices. As for the details:
|
So, my vision here was that we would have a series of places that we would suggest for where an annotation might be helpful. One option is a local variable; another is passing an explicit type parameter to a method or type etc. I don't think we should offer both -- that just seems overwhelming to me. But in any case I figured that eventually this code will grow with logic to gather the full set of possibilities and then pick the "best" thing to suggest. But for now, a local variable feels like a good starting point. Perhaps this is my personal bias: I try to avoid placing annotations anywhere but local variables. In general, I feel like if a type annotation is needed, the code is probably complex enough that I ought to introduce a variable anyway. |
Which note are you referring to specifically? This one, "type annotations or generic parameter binding required"? If so, I agree we should remove it. |
@nikomatsakis - yup, that's the one. |
Maybe it would be better to complain about unresolved variables before doing the |
@arielb1 either way, I think we will want to search the tree to find the place where we should put the suggestion; in general, it's not the case that the obligation span is likely to be what we want, I think, but also I think in general there will be many places one could put an annotation that would influence the type, and we'll want to grow good heuristics for picking the best/easiest one. |
// except according to those terms. | ||
|
||
fn main() { | ||
let (x,) = (vec![],); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @nikomatsakis I removed the note, took another shot at messages and added a new test case. @estebank @arielb1 and @jonathandturner Thanks for the feedback! 👍 |
Which tree? Unresolved Would be nice. Of course, also suppressing ambiguity errors for type variables that have already been reported (or just making all ambiguity errors ICEs after we're sure we can handle that) would be nice. |
@arielb1 OK, I see your point. I agree that it'd be nice to do a walk of the tree and hunt down unresolved inference variables, but it seems to me that the code in question would be roughly the same either way. In other words, we'd still need some logic to walk the tree. I guess we could pull that logic into a bit of code in typeck, which I guess might be nicer, but it also seems reasonably logical to have it in the error-reporting module. Getting the error from an obligation doesn't seem like the worst place to do it -- the only reason for us to ever fail to be able to resolve an obligation to either error or success is because of an uninferred type variable (it's not really specific to the Still, it seems kind of repetitive that we have this writeback phase which diligently visits every type, but we also have to add another one to scour the tree and find them. An alternative is to keep the new code roughly where it is -- that is, have a function in the error-reporting logic for reporting an unconstrained type varable -- and then modify the writeback code to call this helper so we can give a better error in those cases (the current message is not as good). |
@arielb1 and @nikomatsakis : I don't have anything valuable to add to the discussion. That's why I'm spectating 🤔 If you think there will be no significant performance penalties or false positives, I say we get this merged and then start iterating over the better approach, if there'll be any. You can also state any edge cases that you predict. Will be happy to test them |
My feeling is that we should land this as is -- since it provides useful infrastructure for reporting unconstrained types -- and then add calls into writeback for the additional scenarios. @arielb1, are you ok with that? |
yep @bors r+ |
📌 Commit 3fa28cb has been approved by |
Improve error message for uninferrable types rust-lang#38812 Hello, I tried to improve the error message for uninferrable types. The error code is `E0282`. ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:11 | 2 | let x = vec![]; | - ^^^^^^ cannot infer type for `T` | | | consider giving `x` a type | = note: this error originates in a macro outside of the current crate ``` and ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:15 | 2 | let (x,) = (vec![],); | ---- ^^^^^^ cannot infer type for `T` | | | consider giving a type to pattern | = note: this error originates in a macro outside of the current crate ``` Rust compiler now tries to find uninferred `local`s with type `_` and adds them into the error message. I'm probably wrong on wording that I used. Please feel free to suggest better alternatives. Thanks @nikomatsakis for mentoring 🍺 Any comments/feedback is more than welcome! Thank you
Improve error message for uninferrable types rust-lang#38812 Hello, I tried to improve the error message for uninferrable types. The error code is `E0282`. ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:11 | 2 | let x = vec![]; | - ^^^^^^ cannot infer type for `T` | | | consider giving `x` a type | = note: this error originates in a macro outside of the current crate ``` and ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:15 | 2 | let (x,) = (vec![],); | ---- ^^^^^^ cannot infer type for `T` | | | consider giving a type to pattern | = note: this error originates in a macro outside of the current crate ``` Rust compiler now tries to find uninferred `local`s with type `_` and adds them into the error message. I'm probably wrong on wording that I used. Please feel free to suggest better alternatives. Thanks @nikomatsakis for mentoring 🍺 Any comments/feedback is more than welcome! Thank you
Improve error message for uninferrable types rust-lang#38812 Hello, I tried to improve the error message for uninferrable types. The error code is `E0282`. ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:11 | 2 | let x = vec![]; | - ^^^^^^ cannot infer type for `T` | | | consider giving `x` a type | = note: this error originates in a macro outside of the current crate ``` and ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:15 | 2 | let (x,) = (vec![],); | ---- ^^^^^^ cannot infer type for `T` | | | consider giving a type to pattern | = note: this error originates in a macro outside of the current crate ``` Rust compiler now tries to find uninferred `local`s with type `_` and adds them into the error message. I'm probably wrong on wording that I used. Please feel free to suggest better alternatives. Thanks @nikomatsakis for mentoring 🍺 Any comments/feedback is more than welcome! Thank you
Improve error message for uninferrable types rust-lang#38812 Hello, I tried to improve the error message for uninferrable types. The error code is `E0282`. ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:11 | 2 | let x = vec![]; | - ^^^^^^ cannot infer type for `T` | | | consider giving `x` a type | = note: this error originates in a macro outside of the current crate ``` and ```rust error[E0282]: type annotations needed --> /home/cengizIO/issue38812.rs:2:15 | 2 | let (x,) = (vec![],); | ---- ^^^^^^ cannot infer type for `T` | | | consider giving a type to pattern | = note: this error originates in a macro outside of the current crate ``` Rust compiler now tries to find uninferred `local`s with type `_` and adds them into the error message. I'm probably wrong on wording that I used. Please feel free to suggest better alternatives. Thanks @nikomatsakis for mentoring 🍺 Any comments/feedback is more than welcome! Thank you
|
||
err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); | ||
|
||
let expr = self.tcx.hir.expect_expr(cause.body_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be expect_expr
as cause.body_id
can also be a fn
declaration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for highlighting this.
Here's the proposed PR: #40404
Hello,
I tried to improve the error message for uninferrable types. The error code is
E0282
.and
What's changed?
Rust compiler now tries to find uninferred
local
s with type_
and adds them into the error message.Wording
I'm probably wrong on wording that I used. Please feel free to suggest better alternatives.
Appreciation
Thanks @nikomatsakis for mentoring 🍺
Any comments/feedback is more than welcome!
Thank you