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

Type mismatch error should have spans if it's too long #21025

Closed
Manishearth opened this issue Jan 12, 2015 · 10 comments
Closed

Type mismatch error should have spans if it's too long #21025

Manishearth opened this issue Jan 12, 2015 · 10 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Manishearth
Copy link
Member

error: mismatched types: expected `session_types::Session<session_types::Cap<(), session_types::Rec<session_types::Offer<_, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<_, _>, session_types::Snd<_, session_types::Offer<_, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<(), _>, session_types::Snd<_, session_types::Rec<session_types::Offer<_, session_types::Offer<_, session_types::Snd<collections::string::String, session_types::Eps>>>>>>>>>>>>>>, (), _>`, found `session_types::Session<session_types::Cap<(), session_types::Rec<session_types::Offer<session_types::Snd<collections::string::String, session_types::Eps>, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>, session_types::Snd<collections::string::String, session_types::Offer<session_types::Snd<collections::string::String, session_types::Eps>, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>, session_types::Snd<collections::string::String, session_types::Rec<session_types::Offer<session_types::Snd<isize, session_types::Snd<isize, session_types::Var<session_types::Z>>>, session_types::Offer<session_types::Rcv<isize, session_types::Choose<session_types::Snd<collections::string::String, session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>>, session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>>>, session_types::Snd<collections::string::String, session_types::Eps>>>>>>>>>>>>>>, (), ()>` (expected (), found struct collections::string::String) 

It would be useful if there was a note as to where the () and String from (expected (), found struct collections::string::String) were for large types.

An additional note that's shown when the error report is above x (300?) characters which highlights the mismatched types (using something like our ^~~~~~ for code spans) would be useful.

@larsbergstrom
Copy link
Contributor

cc me

@nikomatsakis
Copy link
Contributor

I think there may already be an issue on this (@wycats, do you remember?), but I think another approach here is to change the formatting so that the expected/found types are on separate lines, aligned horizontally, with diffs (identified textually) highlighted in red. This would be fantastic to implement but probably requires a richer alternative to span_err (I'm all for it though)

@nikomatsakis
Copy link
Contributor

Something like span_expected_found_err

@larsbergstrom
Copy link
Contributor

cc @Munksgaard @laumann

@kmcallister
Copy link
Contributor

I think another approach here is to change the formatting so that the expected/found types are on separate lines, aligned horizontally, with diffs (identified textually) highlighted in red.

Big +1. This would be a killer feature and one that every beginner would soon be aware of :)

@kmcallister kmcallister added the A-diagnostics Area: Messages for errors, warnings, and lints label Jan 12, 2015
@Munksgaard
Copy link
Contributor

We frequently run into problems like these. Thankfully we have already seen some significant improvements, primarily that errors like this are now split up into several lines, and that Rust actually tries (with varying success) to point out where it happened. For example, the error mentioned by @Manishearth now looks like this:

foo.rs:172:19: 172:24 error: mismatched types:
 expected `session_types::Session<session_types::Cap<(), session_types::Rec<session_types::Offer<_, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<_, _>, session_types::Snd<_, session_types::Offer<_, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<(), _>, session_types::Snd<_, session_types::Rec<session_types::Offer<_, session_types::Offer<_, session_types::Snd<collections::string::String, session_types::Eps>>>>>>>>>>>>>>, (), _>`,
    found `session_types::Session<session_types::Cap<(), session_types::Rec<session_types::Offer<session_types::Snd<collections::string::String, session_types::Eps>, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>, session_types::Snd<collections::string::String, session_types::Offer<session_types::Snd<collections::string::String, session_types::Eps>, session_types::Rcv<collections::string::String, session_types::Choose<session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>, session_types::Snd<collections::string::String, session_types::Rec<session_types::Offer<session_types::Snd<isize, session_types::Snd<isize, session_types::Var<session_types::Z>>>, session_types::Offer<session_types::Rcv<isize, session_types::Choose<session_types::Snd<collections::string::String, session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>>, session_types::Snd<collections::string::String, session_types::Var<session_types::Z>>>>, session_types::Snd<collections::string::String, session_types::Eps>>>>>>>>>>>>>>, (), ()>`
(expected (),
    found struct `collections::string::String`)
foo.rs:172     connect(cli2, srv());
                              ^~~~~

Which is already much better.

For us, it would be immensely helpful, if a lot of the superfluous stuff was removed from the "found" part of the error message. The "expected" part is nicely trimmed, with underscores replacing irrelevant type parameters. Ideally, the error message would look something like:

foo.rs:172:19: 172:24 error: mismatched types:
 expected `Session<Cap<(), Rec<Offer<_, Rcv<String, Choose<Snd<_, _>, Snd<_, Offer<_, Rcv<String, Choose<Snd<(), _>, _>>>>>>>>>, (), _>`,
    found `Session<Cap<(), Rec<Offer<_, Rcv<String, Choose<Snd<_, _>, Snd<_, Offer<_, Rcv<String, Choose<Snd<String, _>, _>>>>>>>>>, (), ()>`
(expected (),
    found struct `String`)
foo.rs:172     connect(cli2, srv());
                              ^~~~~

(With or without the collections::string:: and session_types:: that I stripped for my sanity)

@Munksgaard
Copy link
Contributor

Or, to put it more simply, consider the following code

struct Foo<T, U> ( u8 );

fn bar(x: Foo<u8, i8>) {

}

fn main() {
  let x: Foo<u8, u8> = Foo(42);
  bar(x);
}

We get the following error message:

foo.rs:9:7: 9:8 error: mismatched types:
 expected `Foo<u8, i8>`,
    found `Foo<u8, i64>`
(expected i8,
    found i64)
foo.rs:9   bar(x);
               ^
error: aborting due to previous error

Ideally, Rust could replace Foo<u8, i64> in the expected part with Foo<_, i64>, since the first type parameter to Foo is not relevant to this error message.

@dhardy
Copy link
Contributor

dhardy commented Jan 26, 2015

Another case:

mismatched types: expected `core::result::Result<lossfunction::scenario::PredictionRecord, Box<misc::OMErrorT + 'static>>`, found `lossfunction::scenario::PredictionRecord` (expected enum core::result::Result, found struct lossfunction::scenario::PredictionRecord)

would be much easier to read if (a) it factored out the common type and (b) suggested a fix:

mismatched types: did you forget to wrap with Ok( ... ) ?
expected: `core::result::Result<P, Box<misc::OMErrorT + 'static>>`
found: `P`
where: `P` = `lossfunction::scenario::PredictionRecord`

@steveklabnik
Copy link
Member

Triage; still lots of room for improvement here.

@estebank
Copy link
Contributor

I can see five possible cases:

1:
expected: `A<B<C, D>, E>`, found: `B<C, D>`  // You likely forgot to use `Ok` or `Some`,
                                             // discussed in previous comments
2:
expected: `A<B<C, D>, E>`, found: `B<X, Y>`  // You likely forgot to use `Ok` and above
                                             // that you're also providing a wrong type
                                             // regardless
3:
expected: `A<B<C, D>, E>`, found: `A<F, E>`  // You provided the wrong type, already
                                             // handled somewhat by the current
                                             // implementation
4:
expected: `A<B<C, D>, E>`, found: `A<F, J>`  // You provided the wrong type for both
                                             // the success and failure types
5:
expected: `B<C, D>`, found: `A<B<C, D>, E>`  // You probably used `Ok` or `Some` when
                                             // you didn't need to

For the 1st case, I like @dhardy's proposal:

expected: `core::result::Result<P, Box<misc::OMErrorT + 'static>>`
   found: `P`
   where: `P` = `lossfunction::scenario::PredictionRecord`

For the 2nd case, I can't think of a nice way to present it over what we already have: the types are simply wrong.

For the 3rd case it currently would look a bit like this, which I don't think is too bad:

 expected `core::result::Result<lossfunction::scenario::PredictionRecord, Box<misc::OMErrorT + 'static>>`,
    found `core::result::Result<&str, Box<misc::OMErrorT + 'static>>`
(expected lossfunction::scenario::PredictionRecord,
    found &str)

but could be changed to look this way to look consistent with the 1st case's (this example is for the 4th case, but it'd look practically the same for the 3rd case):

mismatched types in `core::result::Result<P, Q>`, where `P`, `Q`:
    expected: `P` = `lossfunction::scenario::PredictionRecord`
       found: `P` = `&str`
    expected: `Q` = `Box<misc::OMErrorT + 'static>`
       found: `Q` = `misc::OMErrorT + 'static`

Supporting this case could get hairy quickly. For example, how many type parameters before you are noisier than the current message?

The 5th case is the same as the 1st one, only reversed:

expected: `P`
   found: `core::result::Result<P, Box<misc::OMErrorT + 'static>>`
   where: `P` = `lossfunction::scenario::PredictionRecord`

The way I see it, there's nothing that could be done for the 2nd case, supporting the 4th could be tricky to get right, and the 3rd case is already somewhat clean.

That leaves case 1 and 5 as the most highly actionable messages to work on (finding if there're sub matches on type inequality), with the possibility to clean up the 3rd case slightly as asked by @Munksgaard (replace types parameters that are are equal with underscore on message). Does that look right?

@steveklabnik steveklabnik added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 9, 2017
TimNN added a commit to TimNN/rust that referenced this issue Apr 12, 2017
…, r=nikomatsakis

Highlight and simplify mismatched types

Shorten mismatched types errors by replacing subtypes that are not
different with `_`, and highlighting only the subtypes that are
different.

Given a file

```rust
struct X<T1, T2> {
    x: T1,
    y: T2,
}

fn foo() -> X<X<String, String>, String> {
    X { x: X {x: "".to_string(), y: 2}, y: "".to_string()}
}

fn bar() -> Option<String> {
    "".to_string()
}
```

provide the following output

```rust
error[E0308]: mismatched types
  --> file.rs:6:5
   |
 6 |     X { x: X {x: "".to_string(), y: 2}, y: "".to_string()}
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found {integer}
   |
   = note: expected type `X<X<_, std::string::String>, _>`
                                 ^^^^^^^^^^^^^^^^^^^   // < highlighted
              found type `X<X<_, {integer}>, _>`
                                 ^^^^^^^^^             // < highlighted

error[E0308]: mismatched types
  --> file.rs:6:5
   |
10 |     "".to_string()
   |     ^^^^^^^^^^^^^^ expected struct `std::option::Option`, found `std::string::String`
   |
   = note: expected type `Option<std::string::String>`
                          ^^^^^^^                   ^  // < highlighted
              found type `std::string::String`
```

Fix rust-lang#21025. Re: rust-lang#40186. Follow up to rust-lang#39906.

I'm looking to change how this output is accomplished so that it doesn't create list of strings to pass around, but rather add an elided `Ty` placeholder, and use the same string formatting for normal types. I'll be doing that soonish.

r? @nikomatsakis
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 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

8 participants