diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-12-28 14:13:08 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-28 14:13:08 +0100 |
| commit | 12ac31235151bbce00be0e0324904c3803e5083d (patch) | |
| tree | a263538509e02e4c18cf2523941f6f954455a7fe | |
| parent | d3c43ac244741221393b685423ce771e88e0ac7e (diff) | |
| parent | 5e6dc927f7a935874a08c2c3913f24295711d8f2 (diff) | |
Rollup merge of #80284 - ThePuzzlemaker:issue-80179-fix, r=varkor
Suggest fn ptr rather than fn item and suggest to use `Fn` trait bounds rather than the unique closure type in E0121
Previously, using `_` as a return type in a function that returned a function/closure would provide a diagnostic that would cause a papercut. For example:
```rust
fn f() -> i32 { 0 }
fn fn_ptr() -> _ { f }
fn closure() -> _ { || 0 }
```
would result in this diagnostic:
```rust
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> <anon>:2:16
|
2 | fn fn_ptr() -> _ { f }
| ^
| |
| not allowed in type signatures
| help: replace with the correct return type: `fn() -> i32 {f}`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> <anon>:3:17
|
3 | fn closure() -> _ { || 0 }
| ^
| |
| not allowed in type signatures
| help: replace with the correct return type: `[closure@<anon>:3:21: 3:25]`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0121`.
```
As can be seen, it was suggested to use the function definition return type `fn() -> i32 { f }` which is not valid syntax as a return type. Additionally, closures cause a papercut as unique closure types (notated in this case as `[closure@<anon>:3:21: 3:25]`) are not valid syntax either.
Instead, this PR implements this version of the diagnostic (this example is for the same code featured above):
```rust
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> <anon>:2:16
|
2 | fn fn_ptr() -> _ { f }
| ^
| |
| 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
--> <anon>:3:17
|
3 | fn closure() -> _ { || 0 }
| ^ 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`.
```
As can be seen in this diagnostic, the papercut for returning a function item is fixed by suggesting the usage of a function pointer as the return type. As for closures, it's suggested to use an `Fn`, `FnMut`, or `FnOnce` trait bound (with further reading on closures and `Fn` traits in *The Book* for beginners). I did not implement a suggestion to use `impl Fn() -> i32` syntax as that was out-of-scope for my abilities at the moment, therefore someone in the future may want to implement that. Also, it's possible to use either `impl Trait` syntax, generics, or generics with a `where` clause, and some users may not want to use `impl Trait` syntax for their own reasons.
This PR fixes #80179.
| -rw-r--r-- | compiler/rustc_typeck/src/collect.rs | 27 | ||||
| -rw-r--r-- | src/test/ui/fn/issue-80179.rs | 27 | ||||
| -rw-r--r-- | src/test/ui/fn/issue-80179.stderr | 21 |
3 files changed, 69 insertions, 6 deletions
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index dd4bfc7a751..caa03f79ca2 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) diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs new file mode 100644 index 00000000000..7609b1525cc --- /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 00000000000..63571e71b34 --- /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`. |
