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

Improving type mismatch errors #37384

Closed
sophiajt opened this issue Oct 24, 2016 · 5 comments
Closed

Improving type mismatch errors #37384

sophiajt opened this issue Oct 24, 2016 · 5 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sophiajt
Copy link
Contributor

From: https://internals.rust-lang.org/t/improving-type-mismatch-errors/4263

Background

For a type mismatch error, there often are a known set of steps to transition from one type to another. If it's the first time the user has seen this error, they're forced to go read docs to find the correct API call to do the conversion. This takes time and can be a bit frustration. Luckily, over time your muscle memory will kick in with the known conversion (eg String->&str or &str->String) and it will then just be a minor inconvenience to do the fix.

Improved errors

The idea is pretty simple: have the compiler search the methods on the type looking for a compatible self parameter as the one argument and the expected type as the return type.

For the &str to String case, for example, it may find:

fn to_string(&self) -> String

This can then become a suggestion we give the user. Whereas currently we say:

error[E0308]: mismatched types
 --> <anon>:4:17
  |
4 |   expect_string("foo");
  |                 ^^^^^ expected struct `std::string::String`, found reference
  |
  = note: expected type `std::string::String`
  = note:    found type `&'static str`

We could potentially say:

error[E0308]: mismatched types
 --> <anon>:4:17
  |
4 |   expect_string("foo");
  |                 ^^^^^ expected struct `std::string::String`, found reference
  |
suggestion:
  |   expect_string("foo".to_string());
  |                      ------------ convert to a String

Caveats

Can't grab methods blindly

If we search for this pattern naively, we could potentially suggest methods that have side effects. While, yes, the correct type comes out, the dev could have inadvertently added a difficult to debug issue to their code in the process, just because the compiler told them to.

Also, some methods are very likely not what the user intended, like @GuillaumeGomez 's example:

now when you write "let x: usize = String::new();", it suggests capacity or len method

To prevent this, we may need to annotate methods with a "safe for suggestion" keyword that the suggestion logic can understand.

Multiple steps needed

Sometimes it's more than just one step. While we don't necessarily want to search deeply, we could do a limited number of steps. Assuming something like the "safe for suggestion" feature above, we're in a small, bounded search space and still able to deliver helpful suggestions.

Supporting & and &mut

Since adding an & or &mut is a common task in Rust, we should also add them to the search space for each step (assuming the type is allowed to take that step)

Multiple possibilities

Sometimes there are multiple possibilities for the conversion. It may be through one step (like .to_string() and .into()) or different ways to multi-step to the right type. We'd need to come up with a heuristic here, eg) possibly showing a couple suggestions sorted by the by the shortest in terms of character length.

How do generics/traits factor into this?

I have no idea :slight_smile: This may be easier than it seems, I'm not sure. If it proves to be tricky, maybe we can support them in a later revision of the idea as we get more experience with it?

@sophiajt
Copy link
Contributor Author

cc @nikomatsakis

@oli-obk
Copy link
Contributor

oli-obk commented Oct 25, 2016

For the expected T, got &T case, check for a T: Clone impl

For the expected T, got &U case, it might be as simple as to check for a T: Borrow<U> impl and suggest to_owned().

for all other cases (or those without the appropriate impls), do the more fancy analysis with convert or arbitrary method search.

@GuillaumeGomez
Copy link
Member

For people who might be interested by the status of my work on it: #37388

@GuillaumeGomez
Copy link
Member

GuillaumeGomez commented Oct 25, 2016

For the tag to use for safe suggestion, I propose:

#[safe_suggestion]
fn f() {}

// in case we have multiple suggestions
#[safe_suggestion="this function does this"]
fn f() {}

#[safe_suggestion="this other function does that"]
fn f2() {}

@sanxiyn sanxiyn added the A-diagnostics Area: Messages for errors, warnings, and lints label Oct 26, 2016
@steveklabnik steveklabnik added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 9, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 26, 2017
Centril added a commit to Centril/rust that referenced this issue Aug 9, 2019
Tweak mismatched types error

- Change expected/found for type mismatches in `break`
- Be more accurate when talking about diverging match arms
- Tweak wording of function without a return value
- Suggest calling bare functions when their return value can be coerced to the expected type
- Give more parsing errors when encountering `foo(_, _, _)`

Fix rust-lang#51767, fix rust-lang#62677, fix rust-lang#63136, cc rust-lang#37384, cc rust-lang#35241.
Centril added a commit to Centril/rust that referenced this issue Aug 9, 2019
Tweak mismatched types error

- Change expected/found for type mismatches in `break`
- Be more accurate when talking about diverging match arms
- Tweak wording of function without a return value
- Suggest calling bare functions when their return value can be coerced to the expected type
- Give more parsing errors when encountering `foo(_, _, _)`

Fix rust-lang#51767, fix rust-lang#62677, fix rust-lang#63136, cc rust-lang#37384, cc rust-lang#35241.
Centril added a commit to Centril/rust that referenced this issue Aug 9, 2019
Tweak mismatched types error

- Change expected/found for type mismatches in `break`
- Be more accurate when talking about diverging match arms
- Tweak wording of function without a return value
- Suggest calling bare functions when their return value can be coerced to the expected type
- Give more parsing errors when encountering `foo(_, _, _)`

Fix rust-lang#51767, fix rust-lang#62677, fix rust-lang#63136, cc rust-lang#37384, cc rust-lang#35241, cc rust-lang#51669.
Centril added a commit to Centril/rust that referenced this issue Aug 10, 2019
Tweak mismatched types error

- Change expected/found for type mismatches in `break`
- Be more accurate when talking about diverging match arms
- Tweak wording of function without a return value
- Suggest calling bare functions when their return value can be coerced to the expected type
- Give more parsing errors when encountering `foo(_, _, _)`

Fix rust-lang#51767, fix rust-lang#62677, fix rust-lang#63136, cc rust-lang#37384, cc rust-lang#35241, cc rust-lang#51669.
Centril added a commit to Centril/rust that referenced this issue Aug 10, 2019
Tweak mismatched types error

- Change expected/found for type mismatches in `break`
- Be more accurate when talking about diverging match arms
- Tweak wording of function without a return value
- Suggest calling bare functions when their return value can be coerced to the expected type
- Give more parsing errors when encountering `foo(_, _, _)`

Fix rust-lang#51767, fix rust-lang#62677, fix rust-lang#63136, cc rust-lang#37384, cc rust-lang#35241, cc rust-lang#51669.
@Enselic
Copy link
Member

Enselic commented Sep 14, 2023

Triage: The situation is much better now. For example, this:

fn consume(s: Owned) {}

struct Ref;

struct Owned;

impl From<Ref> for Owned {
    fn from(_: Ref) -> Self {
        Owned
    }
}
fn main() {
    consume(Ref);
}

gives this:

$ rustc +stable ~/src/bin/src/main.rs
error[E0308]: mismatched types
  --> /home/martin/src/bin/src/main.rs:13:13
   |
13 |     consume(Ref);
   |     ------- ^^^ expected `Owned`, found `Ref`
   |     |
   |     arguments to this function are incorrect
   |
note: function defined here
  --> /home/martin/src/bin/src/main.rs:1:4
   |
1  | fn consume(s: Owned) {}
   |    ^^^^^^^ --------
help: call `Into::into` on this expression to convert `Ref` into `Owned`
   |
13 |     consume(Ref.into());
   |                +++++++

and this:

fn consume_string(s: String) {
    println!("Got a String: {}", s);
}

fn main() {
    consume_string("hi");
}

gives this:

$ rustc +stable ~/src/bin/src/main.rs
error[E0308]: mismatched types
 --> /home/martin/src/bin/src/main.rs:6:20
  |
6 |     consume_string("hi");
  |     -------------- ^^^^- help: try using a conversion method: `.to_string()`
  |     |              |
  |     |              expected `String`, found `&str`
  |     arguments to this function are incorrect

Let's close this issue. If there are more type mismatch errors that should be handled, it is better to file that as a new issue with dedicated MCVEs rather than keeping this old issue open.

@Enselic Enselic closed this as not planned Won't fix, can't repro, duplicate, stale Sep 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants