Skip to content

Commit

Permalink
Provide context on E0308 involving fn items
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Jun 22, 2020
1 parent a39c778 commit f84b7e1
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
(ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
let mut values = self.cmp_fn_sig(&sig1, sig2);
values.0.push_normal(format!(
values.0.push_highlighted(format!(
" {{{}}}",
self.tcx.def_path_str_with_substs(*did1, substs1)
));
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_await(err, expr, expected, expr_ty);
self.note_need_for_fn_pointer(err, expected, expr_ty);
}

// Requires that the two types unify, and prints an error message if
Expand Down
42 changes: 42 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5496,6 +5496,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn note_need_for_fn_pointer(
&self,
err: &mut DiagnosticBuilder<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) {
match (&expected.kind, &found.kind) {
(ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
if sig1 != sig2 {
return;
}
err.note(
"different `fn` items always have unique types, even if their signatures are \
the same",
);
err.help(&format!("change the expectation to require function pointer `{}`", sig1));
err.help(&format!(
"if the expectation is due to type inference, cast the expected `fn` to a \
function pointer: `{} as {}`",
self.tcx.def_path_str_with_substs(*did1, substs1),
sig1
));
}
(ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
if sig1 != *sig2 {
return;
}
err.help(&format!("change the expectation to require function pointer `{}`", sig1));
err.help(&format!(
"if the expectation is due to type inference, cast the expected `fn` to a \
function pointer: `{} as {}`",
self.tcx.def_path_str_with_substs(*did, substs),
sig1
));
}
_ => {}
}
}

/// A common error is to add an extra semicolon:
///
/// ```
Expand Down
34 changes: 28 additions & 6 deletions src/test/ui/fn/fn-item-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,44 @@ impl<T> Foo for T { /* `foo` is still default here */ }
fn main() {
eq(foo::<u8>, bar::<u8>);
//~^ ERROR mismatched types
//~| expected fn item `fn(_) -> _ {foo::<u8>}`
//~| found fn item `fn(_) -> _ {bar::<u8>}`
//~| expected fn item, found a different fn item
//~| expected fn item `fn(_) -> _ {foo::<u8>}`
//~| found fn item `fn(_) -> _ {bar::<u8>}`
//~| expected fn item, found a different fn item
//~| different `fn` items always have unique types, even if their signatures are the same
//~| change the expectation to require function pointer
//~| if the expectation is due to type inference, cast the expected `fn` to a function pointer

eq(foo::<u8>, foo::<i8>);
//~^ ERROR mismatched types
//~| expected `u8`, found `i8`
//~| different `fn` items always have unique types, even if their signatures are the same
//~| change the expectation to require function pointer
//~| if the expectation is due to type inference, cast the expected `fn` to a function pointer

eq(bar::<String>, bar::<Vec<u8>>);
//~^ ERROR mismatched types
//~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
//~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
//~| expected struct `std::string::String`, found struct `std::vec::Vec`
//~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
//~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
//~| expected struct `std::string::String`, found struct `std::vec::Vec`
//~| different `fn` items always have unique types, even if their signatures are the same
//~| change the expectation to require function pointer
//~| if the expectation is due to type inference, cast the expected `fn` to a function pointer

// Make sure we distinguish between trait methods correctly.
eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
//~^ ERROR mismatched types
//~| expected `u8`, found `u16`
//~| different `fn` items always have unique types, even if their signatures are the same
//~| change the expectation to require function pointer
//~| if the expectation is due to type inference, cast the expected `fn` to a function pointer

eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
//~^ ERROR mismatched types
//~| expected fn item `fn(_) -> _ {foo::<u8>}`
//~| found fn pointer `fn(_) -> _`
//~| expected fn item, found fn pointer
//~| change the expectation to require function pointer
//~| if the expectation is due to type inference, cast the expected `fn` to a function pointer

eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok!
}
31 changes: 27 additions & 4 deletions src/test/ui/fn/fn-item-type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,57 @@ LL | eq(foo::<u8>, bar::<u8>);
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
found fn item `fn(_) -> _ {bar::<u8>}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expectation to require function pointer `fn(isize) -> isize`
= help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`

error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:19:19
--> $DIR/fn-item-type.rs:22:19
|
LL | eq(foo::<u8>, foo::<i8>);
| ^^^^^^^^^ expected `u8`, found `i8`
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
found fn item `fn(_) -> _ {foo::<i8>}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expectation to require function pointer `fn(isize) -> isize`
= help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`

error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:23:23
--> $DIR/fn-item-type.rs:29:23
|
LL | eq(bar::<String>, bar::<Vec<u8>>);
| ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
|
= note: expected fn item `fn(_) -> _ {bar::<std::string::String>}`
found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expectation to require function pointer `fn(isize) -> isize`
= help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `bar::<std::string::String> as fn(isize) -> isize`

error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:30:26
--> $DIR/fn-item-type.rs:39:26
|
LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
| ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
|
= note: expected fn item `fn() {<u8 as Foo>::foo}`
found fn item `fn() {<u16 as Foo>::foo}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expectation to require function pointer `fn()`
= help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`

error: aborting due to 4 previous errors
error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:46:19
|
LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
found fn pointer `fn(_) -> _`
= help: change the expectation to require function pointer `fn(isize) -> isize`
= help: if the expectation is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`

error: aborting due to 5 previous errors

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

0 comments on commit f84b7e1

Please sign in to comment.