Skip to content

Commit

Permalink
Rollup merge of #100479 - compiler-errors:argument-type-error-improve…
Browse files Browse the repository at this point in the history
…ments, r=lcnr

Argument type error improvements

Motivated by this interesting code snippet:

```rust
#[derive(Copy, Clone)]
struct Wrapper<T>(T);

fn foo(_: fn(i32), _: Wrapper<i32>) {}

fn f(_: u32) {}

fn main() {
    let w = Wrapper::<isize>(1isize);
    foo(f, w);
}
```

Which currently errors like:
```
error[E0308]: arguments to this function are incorrect
  --> src/main.rs:10:5
   |
10 |     foo(f, w);
   |     ^^^ -  - expected `i32`, found `isize`
   |         |
   |         expected `i32`, found `u32`
   |
   = note: expected fn pointer `fn(i32)`
                 found fn item `fn(u32) {f}`
   = note: expected struct `Wrapper<i32>`
              found struct `Wrapper<isize>`
note: function defined here
  --> src/main.rs:4:4
   |
4  | fn foo(_: fn(i32), _: Wrapper<i32>) {}
   |    ^^^ ----------  ---------------
```

Specifically, that double `expected .. found ..` which is very difficult to correlate to the types in the arguments. Also, the fact that "expected `i32`, found `isize`" and the other argument mismatch label don't even really explain what's going on here.

After this PR:
```
error[E0308]: arguments to this function are incorrect
  --> $DIR/two-mismatch-notes.rs:10:5
   |
LL |     foo(f, w);
   |     ^^^
   |
note: expected fn pointer, found fn item
  --> $DIR/two-mismatch-notes.rs:10:9
   |
LL |     foo(f, w);
   |         ^
   = note: expected fn pointer `fn(i32)`
                 found fn item `fn(u32) {f}`
note: expected struct `Wrapper`, found a different struct `Wrapper`
  --> $DIR/two-mismatch-notes.rs:10:12
   |
LL |     foo(f, w);
   |            ^
   = note: expected struct `Wrapper<i32>`
              found struct `Wrapper<isize>`
note: function defined here
  --> $DIR/two-mismatch-notes.rs:4:4
   |
LL | fn foo(_: fn(i32), _: Wrapper<i32>) {}
   |    ^^^ ----------  ---------------

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
```

Yeah, it's a bit verbose, but much clearer IMO.

---

Open to discussions about how this could be further improved. Motivated by `@jyn514's` [tweet](https://mobile.twitter.com/joshuayn514/status/1558042020601634816) here.
  • Loading branch information
compiler-errors authored Aug 14, 2022
2 parents 809fc86 + aa1a07f commit b3e76aa
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 20 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// E0271, like `src/test/ui/issues/issue-39970.stderr`.
#[tracing::instrument(
level = "debug",
skip(self, diag, secondary_span, swap_secondary_and_primary, force_label)
skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label)
)]
pub fn note_type_err(
&self,
Expand All @@ -1434,7 +1434,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
mut values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>,
swap_secondary_and_primary: bool,
force_label: bool,
prefer_label: bool,
) {
let span = cause.span();

Expand Down Expand Up @@ -1612,7 +1612,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
TypeError::ObjectUnsafeCoercion(_) => {}
_ => {
let mut label_or_note = |span: Span, msg: &str| {
if force_label || &[span] == diag.span.primary_spans() {
if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
diag.span_label(span, msg);
} else {
diag.span_note(span, msg);
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
let can_coerce = self.can_coerce(arg_ty, coerced_ty);
if !can_coerce {
return Compatibility::Incompatible(None);
return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts(
ty::error::ExpectedFound::new(true, coerced_ty, arg_ty),
)));
}

// Using probe here, since we don't want this subtyping to affect inference.
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/argument-suggestions/issue-96638.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/issue-96638.rs:8:5
|
LL | f(&x, "");
| ^ -- an argument of type `usize` is missing
| ^ -- -- expected `usize`, found `&str`
| |
| an argument of type `usize` is missing
|
note: function defined here
--> $DIR/issue-96638.rs:1:4
Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/argument-suggestions/issue-97484.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ error[E0061]: this function takes 4 arguments but 7 arguments were supplied
--> $DIR/issue-97484.rs:12:5
|
LL | foo(&&A, B, C, D, E, F, G);
| ^^^ - - - argument of type `F` unexpected
| | |
| ^^^ - - - - argument of type `F` unexpected
| | | |
| | | expected `&E`, found struct `E`
| | argument of type `C` unexpected
| argument of type `B` unexpected
|
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/argument-suggestions/two-mismatch-notes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[derive(Copy, Clone)]
struct Wrapper<T>(T);

fn foo(_: fn(i32), _: Wrapper<i32>) {}

fn f(_: u32) {}

fn main() {
let w = Wrapper::<isize>(1isize);
foo(f, w); //~ ERROR arguments to this function are incorrect
}
29 changes: 29 additions & 0 deletions src/test/ui/argument-suggestions/two-mismatch-notes.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0308]: arguments to this function are incorrect
--> $DIR/two-mismatch-notes.rs:10:5
|
LL | foo(f, w);
| ^^^
|
note: expected `i32`, found `u32`
--> $DIR/two-mismatch-notes.rs:10:9
|
LL | foo(f, w);
| ^
= note: expected fn pointer `fn(i32)`
found fn item `fn(u32) {f}`
note: expected `i32`, found `isize`
--> $DIR/two-mismatch-notes.rs:10:12
|
LL | foo(f, w);
| ^
= note: expected struct `Wrapper<i32>`
found struct `Wrapper<isize>`
note: function defined here
--> $DIR/two-mismatch-notes.rs:4:4
|
LL | fn foo(_: fn(i32), _: Wrapper<i32>) {}
| ^^^ ---------- ---------------

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
10 changes: 6 additions & 4 deletions src/test/ui/issues/issue-18819.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> $DIR/issue-18819.rs:16:5
|
LL | print_x(X);
| ^^^^^^^---
| ||
| |expected reference, found struct `X`
| an argument of type `&str` is missing
| ^^^^^^^--- an argument of type `&str` is missing
|
note: expected reference, found struct `X`
--> $DIR/issue-18819.rs:16:13
|
LL | print_x(X);
| ^
= note: expected reference `&dyn Foo<Item = bool>`
found struct `X`
note: function defined here
Expand Down
18 changes: 12 additions & 6 deletions src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple-errors.rs:6:34
|
LL | let _: Option<(i32, bool)> = Some(1, 2);
| ^^^^ - - argument of type `{integer}` unexpected
| |
| expected tuple, found integer
| ^^^^ - argument of type `{integer}` unexpected
|
note: expected tuple, found integer
--> $DIR/args-instead-of-tuple-errors.rs:6:39
|
LL | let _: Option<(i32, bool)> = Some(1, 2);
| ^
= note: expected tuple `(i32, bool)`
found type `{integer}`
note: tuple variant defined here
Expand All @@ -22,10 +25,13 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple-errors.rs:8:5
|
LL | int_bool(1, 2);
| ^^^^^^^^ - - argument of type `{integer}` unexpected
| |
| expected tuple, found integer
| ^^^^^^^^ - argument of type `{integer}` unexpected
|
note: expected tuple, found integer
--> $DIR/args-instead-of-tuple-errors.rs:8:14
|
LL | int_bool(1, 2);
| ^
= note: expected tuple `(i32, bool)`
found type `{integer}`
note: function defined here
Expand Down
9 changes: 6 additions & 3 deletions src/test/ui/tuple/wrong_argument_ice-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/wrong_argument_ice-3.rs:9:16
|
LL | groups.push(new_group, vec![process]);
| ^^^^ --------- ------------- argument of type `Vec<&Process>` unexpected
| |
| expected tuple, found struct `Vec`
| ^^^^ ------------- argument of type `Vec<&Process>` unexpected
|
note: expected tuple, found struct `Vec`
--> $DIR/wrong_argument_ice-3.rs:9:21
|
LL | groups.push(new_group, vec![process]);
| ^^^^^^^^^
= note: expected tuple `(Vec<String>, Vec<Process>)`
found struct `Vec<String>`
note: associated function defined here
Expand Down

0 comments on commit b3e76aa

Please sign in to comment.