From 3016f55579bfb3a6a130eb75ddfcc699a64f0477 Mon Sep 17 00:00:00 2001 From: Matthew J Perez Date: Wed, 25 Jan 2023 17:10:26 +0000 Subject: [PATCH] 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 --- .../src/infer/error_reporting/suggest.rs | 52 ++++++++++++++++--- tests/ui/fn/fn-compare-mismatch.stderr | 1 + tests/ui/fn/fn-item-type.stderr | 6 ++- tests/ui/fn/fn-pointer-mismatch.stderr | 3 ++ 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 eb7bd7256c674..768cef89f3c43 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 f247ff6cf3f55..b4e71e75fdb9a 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 cb1b88c7ab8f3..9d41243ef1191 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(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(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(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(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::, bar:: as fn(isize) -> isize); | = note: expected fn item `fn(_) -> _ {foo::}` found fn pointer `fn(_) -> _` - = note: fn items are distinct from fn pointers + = help: consider casting the fn item to a fn pointer: `foo:: 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 2dc0710e27e46..e0bd60fbc0b5e 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