From 58f80f2cfc72d44dfb418cdae57127641f4653fd Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:04:11 +0200 Subject: [PATCH 01/11] Initial named fn trait arguments RFC --- text/0000-named-fn-trait-arguments.md | 185 ++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 text/0000-named-fn-trait-arguments.md diff --git a/text/0000-named-fn-trait-arguments.md b/text/0000-named-fn-trait-arguments.md new file mode 100644 index 00000000000..97d733dd084 --- /dev/null +++ b/text/0000-named-fn-trait-arguments.md @@ -0,0 +1,185 @@ +- Feature Name: `named_fn_trait_arguments` +- Start Date: 2026-04-24 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +## Summary +[summary]: #summary + +Allow (optional) named function parameters in `Fn`, `FnMut`, and `FnOnce`. +For example: +```rust +fn parse_my_data( + data: &str, + log: impl Fn(msg: String, priority: usize) +) { } +``` +Similar to named function parameters, these names don't affect rust's semantics. + +## Motivation +[motivation]: #motivation + +### Benefit: Better documentation + +This allows users to better document the meaning of parameters in signatures. This is the primary benefit of this RFC. + +For example, it is not immediately clear what the `String` and `usize` refer to in the type of `log`, providing names like in the example above is much clearer. + +```rust +fn parse_my_data( + data: &str, + log: impl Fn(String, usize) +) { } +``` + +### Benefit: Better LSP hints + +When calling `log` in the body of `parse_my_data`, the LSP can provide the function parameter names as "inlay parameter name hints": +log(`data: `"Message".to_string(), `priority: `1); + +This is a concrete advantage of this approach over using comments to do the same thing, such as in: +```rust +fn parse_my_data( + data: &str, + log: impl Fn(/* msg */ String, /* priority */ usize) +) { } +``` + +### Benefit: Better consistency with `fn` pointers + +Imagine if `parse_my_data` looked like this: +```rust +fn parse_my_data( + data: &str, + log: fn(msg: String, priority: usize) +) { } +``` + +If due to new requirements the user decides that `impl Fn` suits the usecase better, having to remove the parameter names is unintuive. +This RFC removes this problem. + +Note that the syntax for this feature does not exactly match that of `fn` pointers, see the [reference level explanation](#reference-level-explanation). + +## Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +You can give names to parameters in the `Fn`, `FnMut` and `FnOnce` traits to better document the meaning of these parameters, to help people who call your function. +These names are optional and don't have any semantic meaning. Named and unnamed parameters can be mixed, for example: + +```rust +fn parse_my_data( + data: &str, + log: impl Fn(String, priority: usize) +) { } +``` + +## Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +The syntax `Fn`, `FnMut` and `FnOnce` traits is currently not documented in the reference. + +Before this RFC, the syntax rules are: +```grammar,types +ImplTraitParen -> `impl` TraitBoundParen + +TraitBoundParen -> + ( `?` | ForLifetimes )? TypePath TraitBoundParenArgs + | `(` ( `?` | ForLifetimes )? TypePath TraitBoundParenArgs `)` + +TraitBoundParenArgs -> `(` FunctionParametersNoAttr? `)` BareFunctionReturnType? + +FunctionParametersNoAttr -> + Type ( `,` Type )* `,`? + +BareFunctionReturnType -> `->` TypeNoBounds +``` + +After this RFC, the following rules will change: + +```grammar,types +TraitBoundParenArgs -> `(` MaybeNamedFunctionParametersNoAttr? `)` BareFunctionReturnType? + +MaybeNamedFunctionParametersNoAttr -> + MaybeNamedParamNoAttr ( `,` MaybeNamedParamNoAttr )* `,`? + +MaybeNamedParamNoAttr -> + ( ( IDENTIFIER | `_` ) `:` )? Type +``` + +Note that this means that: + +- Attributes are not allowed on parameters of these traits. This remains unchanged from the current situation. The following will not work: + ```rust + fn test(x: impl Fn(#[allow(unused)] msg: String, priority: usize), y: usize) { } + ``` + Note that attributes are already allowed on `fn` pointers: + ```rust + fn test(x: fn(#[allow(unused)] msg: String, priority: usize), y: usize) { } + ``` + The reason why attributes are not allowed is to keep this RFC and the implementation simple, and because I don't see a use for them. + +- This syntax does not match that of `fn` pointers exactly. + For historic reasons, the following `fn` pointer type is allowed: + ```rust + #[cfg(false)] + type T = fn(mut x: (), &x: (), &&x: (), false: (), &_: (), &true: ()); + ``` + But this RFC proposes that the following `impl Fn` type is not allowed: + + ```rust + #[cfg(false)] + impl Fn(mut x: (), &x: (), &&x: (), false: (), &_: (), &true: ()); + ``` + + The names of function parameters are limited to ``IDENTIFIER | `_` ``. + The reason why we don't match the syntax of `fn` pointer types is because the syntax was a historic mistake and we should not repeat that. + +## Drawbacks +[drawbacks]: #drawbacks + +* This makes the syntax of `impl Fn` and friends slightly more complicated +* This makes the syntax of `impl Fn` and friends inconsistent with that of `fn` pointers. + +## Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +* An alternative would be to match the `fn` pointer syntax perfectly. This would make the implementation more complicated, without much benefit other than consistency. +* This needs to be implemented in the language, it cannot be provided by a macro or library as it +* This makes Rust code easier to read, as it adds better ways to document function signatures. + +## Prior art +[prior-art]: #prior-art + +In Rust, this is already allowed in `fn` pointers: +```rust +type LogFunction = fn(msg: String, priority: usize); +``` + +In TypeScript: +```ts +type LogFunction = (msg: string, priority: number) => void; +``` + +In Kotlin: +```kotlin +fun log(data: String, logFunction: (msg: String, priority: Int) -> Unit) { } +``` + +## Unresolved questions +[unresolved-questions]: #unresolved-questions + +* Should duplicate parameter names be allowed in named fn trait arguments? This is currently allowed for `fn` pointers and other functions without an accompanying `Body`. + ```rust + type T = fn(x: usize, x: usize); + ``` + ```rust + trait Test { + fn thing(x: usize, x: usize); + } + ``` + +## Future possibilities +[future-possibilities]: #future-possibilities + +* We could allow attributes on `impl Fn` parameters in the future. + From d756ee54e5507c5e5fc88c88f95815b8de699d65 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:06:10 +0200 Subject: [PATCH 02/11] Rename file --- ...n-trait-arguments.md => 3955-named-fn-trait-parameters.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename text/{0000-named-fn-trait-arguments.md => 3955-named-fn-trait-parameters.md} (97%) diff --git a/text/0000-named-fn-trait-arguments.md b/text/3955-named-fn-trait-parameters.md similarity index 97% rename from text/0000-named-fn-trait-arguments.md rename to text/3955-named-fn-trait-parameters.md index 97d733dd084..94239e611d6 100644 --- a/text/0000-named-fn-trait-arguments.md +++ b/text/3955-named-fn-trait-parameters.md @@ -1,6 +1,6 @@ -- Feature Name: `named_fn_trait_arguments` +- Feature Name: `named_fn_trait_parameters` - Start Date: 2026-04-24 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3955](https://github.com/rust-lang/rfcs/pull/3955) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) ## Summary From 2e51eccbe79adefe220e0bb585f6ec6425345290 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:07:29 +0200 Subject: [PATCH 03/11] Fix typo in summary --- text/3955-named-fn-trait-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index 94239e611d6..3111ce80d53 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -14,7 +14,7 @@ fn parse_my_data( log: impl Fn(msg: String, priority: usize) ) { } ``` -Similar to named function parameters, these names don't affect rust's semantics. +Similar to named function pointer parameters, these names don't affect rust's semantics. ## Motivation [motivation]: #motivation From caff5dcf20b8d111dcc4180b56cf60f732a32b57 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:43:38 +0200 Subject: [PATCH 04/11] Clarify that this change also applies to trait bounds --- text/3955-named-fn-trait-parameters.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index 3111ce80d53..1eb293c0b99 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -73,6 +73,16 @@ fn parse_my_data( ) { } ``` +This same syntax also applies to `Fn`, `FnMut` and `FnOnce` trait bounds, for example: +```rust +fn parse_my_data< + L: Fn(msg: String, priority: usize) +>( + data: &str, + log: L +) { } +``` + ## Reference-level explanation [reference-level-explanation]: #reference-level-explanation From 93db0a73ed840dc5efe6cb5511f7e65927d4db50 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:44:15 +0200 Subject: [PATCH 05/11] Reword the inconsistency drawback --- text/3955-named-fn-trait-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index 1eb293c0b99..f2f449bafd8 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -148,7 +148,7 @@ Note that this means that: [drawbacks]: #drawbacks * This makes the syntax of `impl Fn` and friends slightly more complicated -* This makes the syntax of `impl Fn` and friends inconsistent with that of `fn` pointers. +* This keeps the syntax of `impl Fn` and friends inconsistent with that of `fn` pointers, as to avoid the historic mistakes mentioned in the [reference level explanation](#reference-level-explanation). ## Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives From dfc02d20c5c191068316c1aebe953e70f858c5cb Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:55:00 +0200 Subject: [PATCH 06/11] Mention that names should show up on rustdoc --- text/3955-named-fn-trait-parameters.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index f2f449bafd8..b85da4ea9d4 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -32,6 +32,8 @@ fn parse_my_data( ) { } ``` +The parameter names should also show up on rustdoc. + ### Benefit: Better LSP hints When calling `log` in the body of `parse_my_data`, the LSP can provide the function parameter names as "inlay parameter name hints": From 12227d9e43c0531eff894085019061ad967b4c3f Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 24 Apr 2026 16:58:09 +0200 Subject: [PATCH 07/11] Rewrite syntax change in the reference level explanation --- text/3955-named-fn-trait-parameters.md | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index b85da4ea9d4..4daf61bcae2 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -92,30 +92,17 @@ The syntax `Fn`, `FnMut` and `FnOnce` traits is currently not documented in the Before this RFC, the syntax rules are: ```grammar,types -ImplTraitParen -> `impl` TraitBoundParen - -TraitBoundParen -> - ( `?` | ForLifetimes )? TypePath TraitBoundParenArgs - | `(` ( `?` | ForLifetimes )? TypePath TraitBoundParenArgs `)` - -TraitBoundParenArgs -> `(` FunctionParametersNoAttr? `)` BareFunctionReturnType? - -FunctionParametersNoAttr -> - Type ( `,` Type )* `,`? - -BareFunctionReturnType -> `->` TypeNoBounds +TypePathFn -> `(` TypePathFnInputs? `)` (`->` TypeNoBounds)? + +TypePathFnInputs -> Type (`,` Type)* `,`? ``` -After this RFC, the following rules will change: +After this RFC, the `TypePathFnInputs` rule will be replaced by: ```grammar,types -TraitBoundParenArgs -> `(` MaybeNamedFunctionParametersNoAttr? `)` BareFunctionReturnType? +TypePathFnInputs -> TypePathFnInput (`,` TypePathFnInput)* `,`? -MaybeNamedFunctionParametersNoAttr -> - MaybeNamedParamNoAttr ( `,` MaybeNamedParamNoAttr )* `,`? - -MaybeNamedParamNoAttr -> - ( ( IDENTIFIER | `_` ) `:` )? Type +TypePathFnInput -> ( ( IDENTIFIER | `_` ) `:` )? Type ``` Note that this means that: From 8e2948e57c82aad233cb1a07e795074ea6bdf279 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 25 Apr 2026 14:01:30 +0200 Subject: [PATCH 08/11] Make explicit that this RFC affects all traits with parenthesized generic argument lists --- text/3955-named-fn-trait-parameters.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index 4daf61bcae2..835f4d5998e 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -6,7 +6,7 @@ ## Summary [summary]: #summary -Allow (optional) named function parameters in `Fn`, `FnMut`, and `FnOnce`. +Allow (optional) named function parameters in parenthesized generic argument lists, such as those of `Fn`, `FnMut`, `FnOnce`, `AsyncFn`, `AsyncFnMut`, and `AsyncFnOnce`. For example: ```rust fn parse_my_data( @@ -65,7 +65,7 @@ Note that the syntax for this feature does not exactly match that of `fn` pointe ## Guide-level explanation [guide-level-explanation]: #guide-level-explanation -You can give names to parameters in the `Fn`, `FnMut` and `FnOnce` traits to better document the meaning of these parameters, to help people who call your function. +You can give names to parameters to the `Fn` trait and its friends to better document the meaning of these parameters, to help people who call your function. These names are optional and don't have any semantic meaning. Named and unnamed parameters can be mixed, for example: ```rust @@ -75,7 +75,7 @@ fn parse_my_data( ) { } ``` -This same syntax also applies to `Fn`, `FnMut` and `FnOnce` trait bounds, for example: +This same syntax also applies to trait bounds, for example: ```rust fn parse_my_data< L: Fn(msg: String, priority: usize) @@ -88,9 +88,7 @@ fn parse_my_data< ## Reference-level explanation [reference-level-explanation]: #reference-level-explanation -The syntax `Fn`, `FnMut` and `FnOnce` traits is currently not documented in the reference. - -Before this RFC, the syntax rules are: +Before this RFC, the syntax rules of parenthesized generic argument lists are: ```grammar,types TypePathFn -> `(` TypePathFnInputs? `)` (`->` TypeNoBounds)? From 036daffe8a48a242861c3c8503d8fe6b078d0b96 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 25 Apr 2026 14:04:01 +0200 Subject: [PATCH 09/11] Clarify that attributes on parameters could be useful --- text/3955-named-fn-trait-parameters.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index 835f4d5998e..ed04fbbcf72 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -107,13 +107,14 @@ Note that this means that: - Attributes are not allowed on parameters of these traits. This remains unchanged from the current situation. The following will not work: ```rust - fn test(x: impl Fn(#[allow(unused)] msg: String, priority: usize), y: usize) { } + fn test(x: impl Fn(#[cfg(...)] msg: String, priority: usize), y: usize) { } ``` Note that attributes are already allowed on `fn` pointers: ```rust - fn test(x: fn(#[allow(unused)] msg: String, priority: usize), y: usize) { } + fn test(x: fn(#[cfg(...)] msg: String, priority: usize), y: usize) { } ``` - The reason why attributes are not allowed is to keep this RFC and the implementation simple, and because I don't see a use for them. + The reason why attributes are not allowed is to keep this RFC and the implementation simple. + Allowing attributes such as `#[cfg(...)]` could be useful, but is out of scope for this RFC. - This syntax does not match that of `fn` pointers exactly. For historic reasons, the following `fn` pointer type is allowed: From 2c76a4532c8dfec9ff08a9d6a2f800d818b56460 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 25 Apr 2026 14:05:13 +0200 Subject: [PATCH 10/11] Fix truncated sentence in rationale about why this needs to be a language change --- text/3955-named-fn-trait-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index ed04fbbcf72..f9b0a19ee5e 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -142,7 +142,7 @@ Note that this means that: [rationale-and-alternatives]: #rationale-and-alternatives * An alternative would be to match the `fn` pointer syntax perfectly. This would make the implementation more complicated, without much benefit other than consistency. -* This needs to be implemented in the language, it cannot be provided by a macro or library as it +* This needs to be implemented in the language, it cannot be provided by a macro or library as it affects syntactic sugar of the language itself. * This makes Rust code easier to read, as it adds better ways to document function signatures. ## Prior art From 15d8dc32847de41f969016db3e27366253e35766 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 25 Apr 2026 14:23:16 +0200 Subject: [PATCH 11/11] Rewrite the reference-level explanation --- text/3955-named-fn-trait-parameters.md | 66 ++++++++++++++++---------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/text/3955-named-fn-trait-parameters.md b/text/3955-named-fn-trait-parameters.md index f9b0a19ee5e..dc2f3153f3a 100644 --- a/text/3955-named-fn-trait-parameters.md +++ b/text/3955-named-fn-trait-parameters.md @@ -103,40 +103,54 @@ TypePathFnInputs -> TypePathFnInput (`,` TypePathFnInput)* `,`? TypePathFnInput -> ( ( IDENTIFIER | `_` ) `:` )? Type ``` -Note that this means that: +Below are two chapters on some design tradeoffs made here. -- Attributes are not allowed on parameters of these traits. This remains unchanged from the current situation. The following will not work: - ```rust - fn test(x: impl Fn(#[cfg(...)] msg: String, priority: usize), y: usize) { } - ``` - Note that attributes are already allowed on `fn` pointers: - ```rust - fn test(x: fn(#[cfg(...)] msg: String, priority: usize), y: usize) { } - ``` - The reason why attributes are not allowed is to keep this RFC and the implementation simple. - Allowing attributes such as `#[cfg(...)]` could be useful, but is out of scope for this RFC. +### Attributes are not allowed on parenthesized generic argument lists +Attributes are not allowed on parameters of these traits. This remains unchanged from the current situation. The following will not work: +```rust +fn test(x: impl Fn(#[cfg(...)] msg: String, priority: usize), y: usize) { } +``` +Note that attributes are already allowed on `fn` pointers: +```rust +fn test(x: fn(#[cfg(...)] msg: String, priority: usize), y: usize) { } +``` +The reason why attributes are not allowed is to keep this RFC and the implementation simple. +Allowing attributes such as `#[cfg(...)]` could be useful, but is out of scope for this RFC. +This choice is the most safe and conservative choice, attributes could be allowed in the future. -- This syntax does not match that of `fn` pointers exactly. - For historic reasons, the following `fn` pointer type is allowed: - ```rust - #[cfg(false)] - type T = fn(mut x: (), &x: (), &&x: (), false: (), &_: (), &true: ()); - ``` - But this RFC proposes that the following `impl Fn` type is not allowed: - - ```rust - #[cfg(false)] - impl Fn(mut x: (), &x: (), &&x: (), false: (), &_: (), &true: ()); - ``` +### Patterns are not allowed in parenthesized generic argument lists +This syntax is not consistent with other features in the language. +The names of function parameters are limited to ``IDENTIFIER | `_` ``. +This choice is made because it is the most safe and conservative choice, keeping the option open to allow patterns in the future if desired. +Below is a comparison with two other language features: + +#### `fn` pointers +This is unlike `fn` pointers, which allows a `RestrictedPat` (and then semantically rejects anything other than identifiers). +Therefore, the following program compiles: +```rust +#[cfg(false)] +type F = fn(mut x: (), &x: (), &&x: (), false: (), &_: (), &true: ()); +``` +``` +RestrictedPat = Ident | "&" Ident | "&&" Ident | "mut" CommonIdent; +Ident = CommonIdent | ReservedIdent (* includes `_`, `false`, `true` *) +``` - The names of function parameters are limited to ``IDENTIFIER | `_` ``. - The reason why we don't match the syntax of `fn` pointer types is because the syntax was a historic mistake and we should not repeat that. +#### trait functions without bodies +This is also unlike trait functions without bodies. Arbitrary patterns are allowed (and then semantically anything other than identifiers is rejected). +Therefore, the following program compiles: +```rust +#[cfg(false)] +trait Test { + fn x((x, y): usize); +} +``` ## Drawbacks [drawbacks]: #drawbacks * This makes the syntax of `impl Fn` and friends slightly more complicated -* This keeps the syntax of `impl Fn` and friends inconsistent with that of `fn` pointers, as to avoid the historic mistakes mentioned in the [reference level explanation](#reference-level-explanation). +* This keeps the syntax of `impl Fn` and friends inconsistent with that of `fn` pointers nor functions in trait definitions, for the reasoning about this see [reference level explanation](#reference-level-explanation). ## Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives