Skip to content
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

Merged
merged 4 commits into from
Feb 8, 2017
Merged

Improve error message for uninferrable types #38812 #39361

merged 4 commits into from
Feb 8, 2017

Conversation

cengiz-io
Copy link
Contributor

@cengiz-io cengiz-io commented Jan 28, 2017

Hello,

I tried to improve the error message for uninferrable types. The error code is E0282.

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

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

What's changed?

Rust compiler now tries to find uninferred locals 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

@rust-highfive
Copy link
Collaborator

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.

@nikomatsakis
Copy link
Contributor

r? @nikomatsakis

@nikomatsakis
Copy link
Contributor

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 x has type Vec<_>, we just don't know what the _ is.

"unable to fully infer type(s)");

err.note("type annotations or generic parameter binding required");
err.span_label(cause.span, &format!("cannot infer type"));
Copy link
Contributor

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.

Copy link
Contributor Author

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)");
Copy link
Contributor

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 :)

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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
Copy link
Contributor

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![],);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@nikomatsakis
Copy link
Contributor

Hmm also this "note: type annotations or generic parameter binding required" feels a bit superfluous. I wonder where that comes from.

@estebank
Copy link
Contributor

I feel the output would be slightly more helpful with something along the lines of:

error[E0282]: unable to fully infer type
  --> $DIR/missing-type-parameter.rs:14:5
   |
10 |     let x = Vec::new();
   |         -   ^^^^^^^^^^ cannot infer type for `T`
   |         |   |
   |         |   consider using `Vec::new<T>()` here, where `T` would be the appropriate type
   |         consider using `x: Vec<T>` here, where `T` would be the appropriate type
   = note: type annotations or generic parameter binding required
error[E0282]: unable to fully infer types
  --> $DIR/missing-type-parameter.rs:14:5
   |
10 |     let x = foo();
   |         -   ^^^^^ cannot infer type for `X` and `Y`
   |         |   |
   |         |   consider using `foo<(X, Y)>()` here, where `X` and `Y` would be the appropriate types
   |         consider using `x: (X, Y)` here, where `X` and `Y` would be the appropriate types
   = note: type annotations or generic parameter binding required

Thoughts?

@sophiajt
Copy link
Contributor

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:

  • I'm not a fan of the note. Do we need it?
  • I might make the secondary label "try explicitly giving x a type"
  • @nikomatsakis I do like the idea of telling us to fill in the blank, but I'm not sure of the best wording for that case.

@nikomatsakis
Copy link
Contributor

@jonathandturner @estebank

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.

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.

@nikomatsakis
Copy link
Contributor

@jonathandturner

I'm not a fan of the note. Do we need it?

Which note are you referring to specifically? This one, "type annotations or generic parameter binding required"? If so, I agree we should remove it.

@sophiajt
Copy link
Contributor

@nikomatsakis - yup, that's the one.

@arielb1
Copy link
Contributor

arielb1 commented Feb 1, 2017

Maybe it would be better to complain about unresolved variables before doing the select_all_or_error call (which catches unresolved variables in most cases when resolving VAR: Sized)? It's not like you are going to resolve anything after the final selection. Then we can just span the variable directly.

@nikomatsakis
Copy link
Contributor

@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![],);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cengiz-io
Copy link
Contributor Author

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! 👍

@arielb1
Copy link
Contributor

arielb1 commented Feb 2, 2017

@nikomatsakis

Which tree? Unresolved _: Sized obligations aren't a particularly good place to find missing type annotations. A typeck body pass that
a) finds missing type annotations
b) reports the correct error for them

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.

@nikomatsakis
Copy link
Contributor

@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 Sized trait), right? However, I guess there are various corner cases where we don't encounter the error until writeback (e.g., let _x = []).

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).

@cengiz-io
Copy link
Contributor Author

@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

@nikomatsakis
Copy link
Contributor

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?

@arielb1
Copy link
Contributor

arielb1 commented Feb 6, 2017

yep

@bors r+

@bors
Copy link
Contributor

bors commented Feb 6, 2017

📌 Commit 3fa28cb has been approved by arielb1

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Feb 7, 2017
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
frewsxcv added a commit to frewsxcv/rust that referenced this pull request Feb 7, 2017
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
bors added a commit that referenced this pull request Feb 7, 2017
Rollup of 15 pull requests

- Successful merges: #38764, #39361, #39426, #39462, #39482, #39557, #39561, #39582, #39583, #39587, #39598, #39599, #39601, #39602, #39604
- Failed merges:
frewsxcv added a commit to frewsxcv/rust that referenced this pull request Feb 8, 2017
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
frewsxcv added a commit to frewsxcv/rust that referenced this pull request Feb 8, 2017
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
bors added a commit that referenced this pull request Feb 8, 2017
Rollup of 13 pull requests

- Successful merges: #38764, #39361, #39372, #39374, #39400, #39426, #39431, #39459, #39482, #39545, #39593, #39620, #39621
- Failed merges:
@bors bors merged commit 3fa28cb into rust-lang:master Feb 8, 2017

err.span_label(cause.span, &format!("cannot infer type for `{}`", name));

let expr = self.tcx.hir.expect_expr(cause.body_id);
Copy link
Member

@eddyb eddyb Mar 7, 2017

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.

Copy link
Contributor Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants