Skip to content

Recover from malformed trait bounds of the form Fn<'a>() #103490

Closed
@fmease

Description

@fmease

The following code:

fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}

currently produces a heap of semi-helpful diagnostics:

stderr (7 errors)
error: unexpected lifetime `'a` in pattern
 --> src/lib.rs:1:26
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |                          ^^ help: remove the lifetime

error: expected one of `:` or `|`, found `->`
 --> src/lib.rs:1:34
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |                                  ^^ expected one of `:` or `|`

error: expected one of `)`, `+`, `,`, or `::`, found `(`
 --> src/lib.rs:1:24
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |                        ^
  |                        |
  |                        expected one of `)`, `+`, `,`, or `::`
  |                        help: missing `,`

error[E0261]: use of undeclared lifetime name `'a`
 --> src/lib.rs:1:21
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |                     ^^ undeclared lifetime
  |
  = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the bound lifetime-generic with a new `'a` lifetime
  |
1 | fn f(_: impl for<'a> FnOnce<'a>(&'a str) -> bool) {}
  |              +++++++
help: consider introducing lifetime `'a` here
  |
1 | fn f<'a>(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |     ++++

error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
 --> src/lib.rs:1:14
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |              ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()`
  |
  = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information

error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
 --> src/lib.rs:1:14
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |              ^^^^^^---- help: remove these generics
  |              |
  |              expected 0 lifetime arguments

error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
 --> src/lib.rs:1:14
  |
1 | fn f(_: impl FnOnce<'a>(&'a str) -> bool) {}
  |              ^^^^^^ expected 1 generic argument
  |
help: add missing generic argument
  |
1 | fn f(_: impl FnOnce<'a, Args>(&'a str) -> bool) {}
  |                       ++++++

when instead we could special-case this and emit a single (or at least fewer) diagnostic that suggests the following:

- impl FnOnce<'a>(&'a str) -> bool
+ impl for<'a> FnOnce(&'a str) -> bool

If the bound in not inside impl Trait, like in:

fn f<F>(_: F) where F: FnOnce<'a>(&'a str) -> bool {}

we currently emit the following:

error: expected one of `+`, `,`, `::`, or `{`, found `(`
 --> src/lib.rs:1:34
  |
1 | fn f<F>(_: F) where F: FnOnce<'a>(&'a str) -> bool {}
  |                                  ^ expected one of `+`, `,`, `::`, or `{`

which is less verbose for sure but still, we should provide the same suggestion I propose above.

Related issue: #103487.

@rustbot label A-parser A-suggestion-diagnostics D-newcomer-roadblock

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-parserArea: The lexing & parsing of Rust source code to an ASTA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions