about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew J Perez <matt@mperez.io>2023-01-25 17:10:26 +0000
committerMatthew J Perez <matt@mperez.io>2023-01-26 05:07:34 +0000
commit3016f55579bfb3a6a130eb75ddfcc699a64f0477 (patch)
tree8614e30edcb3fb82f8e82e93974637edee929a3e
parent2a17174ee639f8e0a3cee307d5685d38beb474ba (diff)
downloadrust-3016f55579bfb3a6a130eb75ddfcc699a64f0477.tar.gz
rust-3016f55579bfb3a6a130eb75ddfcc699a64f0477.zip
improve fn pointer notes
- add note and suggestion for casting both expected and found fn items
  to fn pointers
- add note for casting expected fn item to fn pointer
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs52
-rw-r--r--tests/ui/fn/fn-compare-mismatch.stderr1
-rw-r--r--tests/ui/fn/fn-item-type.stderr6
-rw-r--r--tests/ui/fn/fn-pointer-mismatch.stderr3
4 files changed, 53 insertions, 9 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index eb7bd7256c6..768cef89f3c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -380,7 +380,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     return;
                 }
 
-                let (msg, sugg) = match (expected.is_ref(), found.is_ref()) {
+                let (msg, sug) = match (expected.is_ref(), found.is_ref()) {
                     (true, false) => {
                         let msg = "consider using a reference";
                         let sug = format!("&{fn_name}");
@@ -404,7 +404,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         (msg, sug)
                     }
                 };
-                diag.span_suggestion(span, msg, &sugg, Applicability::MaybeIncorrect);
+                diag.span_suggestion(span, msg, sug, Applicability::MaybeIncorrect);
             }
             (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
                 let expected_sig =
@@ -412,14 +412,50 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let found_sig =
                     &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2));
 
-                if self.same_type_modulo_infer(*found_sig, *expected_sig) {
-                    diag.note(
-                    "different fn items have unique types, even if their signatures are the same",
-                    );
+                if self.same_type_modulo_infer(*expected_sig, *found_sig) {
+                    diag.note("different fn items have unique types, even if their signatures are the same");
+                }
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig)
+                    || !found_sig.is_suggestable(self.tcx, true)
+                    || !expected_sig.is_suggestable(self.tcx, true)
+                    || ty::util::is_intrinsic(self.tcx, *did1)
+                    || ty::util::is_intrinsic(self.tcx, *did2)
+                {
+                    return;
                 }
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
+                let sug = if found.is_ref() {
+                    format!("&({fn_name} as {found_sig})")
+                } else {
+                    format!("{fn_name} as {found_sig}")
+                };
+
+                let msg = format!(
+                    "consider casting both fn items to fn pointers using `as {expected_sig}`"
+                );
+
+                diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
             }
-            (ty::FnDef(_, _), ty::FnPtr(_)) => {
-                diag.note("fn items are distinct from fn pointers");
+            (ty::FnDef(did, substs), ty::FnPtr(sig)) => {
+                let expected_sig =
+                    &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did).subst(self.tcx, substs));
+                let found_sig = &(self.normalize_fn_sig)(*sig);
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig) {
+                    return;
+                }
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did, substs);
+
+                let casting = if expected.is_ref() {
+                    format!("&({fn_name} as {found_sig})")
+                } else {
+                    format!("{fn_name} as {found_sig}")
+                };
+
+                diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
             }
             _ => {
                 return;
diff --git a/tests/ui/fn/fn-compare-mismatch.stderr b/tests/ui/fn/fn-compare-mismatch.stderr
index f247ff6cf3f..b4e71e75fdb 100644
--- a/tests/ui/fn/fn-compare-mismatch.stderr
+++ b/tests/ui/fn/fn-compare-mismatch.stderr
@@ -20,6 +20,7 @@ LL |     let x = f == g;
    = note: expected fn item `fn() {f}`
               found fn item `fn() {g}`
    = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn()`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr
index cb1b88c7ab8..9d41243ef11 100644
--- a/tests/ui/fn/fn-item-type.stderr
+++ b/tests/ui/fn/fn-item-type.stderr
@@ -14,6 +14,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:29:19
@@ -31,6 +32,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:34:23
@@ -48,6 +50,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:41:26
@@ -65,6 +68,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:46:19
@@ -76,7 +80,7 @@ LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
            found fn pointer `fn(_) -> _`
-   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo::<u8> as fn(isize) -> isize`
 note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr
index 2dc0710e27e..e0bd60fbc0b 100644
--- a/tests/ui/fn/fn-pointer-mismatch.stderr
+++ b/tests/ui/fn/fn-pointer-mismatch.stderr
@@ -9,6 +9,7 @@ LL |     let g = if n % 2 == 0 { &foo } else { &bar };
    = note: expected reference `&fn(u32) -> u32 {foo}`
               found reference `&fn(u32) -> u32 {bar}`
    = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:23:9
@@ -21,6 +22,7 @@ LL |     a = bar;
    = note: expected fn item `fn(_) -> _ {foo}`
               found fn item `fn(_) -> _ {bar}`
    = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:31:18
@@ -35,6 +37,7 @@ LL |     b = Box::new(bar);
    = note: different fn items have unique types, even if their signatures are the same
 note: associated function defined here
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:36:29