From 4f6be466fdec69dbf6ce768d41a43acf0fc3b47b Mon Sep 17 00:00:00 2001 From: ThePuzzlemaker Date: Mon, 21 Dec 2020 20:23:21 -0600 Subject: [PATCH 1/2] Suggest fn ptr rather than fn item and suggest to use `Fn` trait bounds rather than the unique closure type in E0121 This is a squash of the titular commit along with these minor commits: - Improve note - Improve note pt2 --- compiler/rustc_typeck/src/collect.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index bc6b2037c184e..ebbcf6304b65a 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1544,12 +1544,27 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let mut diag = bad_placeholder_type(tcx, visitor.0); let ret_ty = fn_sig.output(); if ret_ty != tcx.ty_error() { - diag.span_suggestion( - ty.span, - "replace with the correct return type", - ret_ty.to_string(), - Applicability::MaybeIncorrect, - ); + if !ret_ty.is_closure() { + let ret_ty_str = match ret_ty.kind() { + // Suggest a function pointer return type instead of a unique function definition + // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid + // syntax) + ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(), + _ => ret_ty.to_string(), + }; + diag.span_suggestion( + ty.span, + "replace with the correct return type", + ret_ty_str, + Applicability::MaybeIncorrect, + ); + } else { + // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds + // to prevent the user from getting a papercut while trying to use the unique closure + // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`). + diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); + diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html"); + } } diag.emit(); ty::Binder::bind(fn_sig) From 5e6dc927f7a935874a08c2c3913f24295711d8f2 Mon Sep 17 00:00:00 2001 From: ThePuzzlemaker Date: Tue, 22 Dec 2020 13:25:37 -0600 Subject: [PATCH 2/2] Add regression test for #80179 --- src/test/ui/fn/issue-80179.rs | 27 +++++++++++++++++++++++++++ src/test/ui/fn/issue-80179.stderr | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/test/ui/fn/issue-80179.rs create mode 100644 src/test/ui/fn/issue-80179.stderr diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs new file mode 100644 index 0000000000000..7609b1525cc90 --- /dev/null +++ b/src/test/ui/fn/issue-80179.rs @@ -0,0 +1,27 @@ +// Functions with a type placeholder `_` as the return type should +// show a function pointer suggestion when given a function item +// and suggest how to return closures correctly from a function. +// This is a regression test of #80179 + +fn returns_i32() -> i32 { + 0 +} + +fn returns_fn_ptr() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +//~| NOTE not allowed in type signatures +//~| HELP replace with the correct return type +//~| SUGGESTION fn() -> i32 + returns_i32 +} + +fn returns_closure() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +//~| NOTE not allowed in type signatures +//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound +//~| NOTE for more information on `Fn` traits and closure types, see +// https://doc.rust-lang.org/book/ch13-01-closures.html + || 0 +} + +fn main() {} diff --git a/src/test/ui/fn/issue-80179.stderr b/src/test/ui/fn/issue-80179.stderr new file mode 100644 index 0000000000000..63571e71b34f4 --- /dev/null +++ b/src/test/ui/fn/issue-80179.stderr @@ -0,0 +1,21 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80179.rs:10:24 + | +LL | fn returns_fn_ptr() -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `fn() -> i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80179.rs:18:25 + | +LL | fn returns_closure() -> _ { + | ^ not allowed in type signatures + | + = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound + = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0121`.