From 03c3d00ee37833252f45860c917e40bcbc3e528d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 11 Aug 2026 20:47:40 +0200 Subject: [PATCH 1/4] Make inputs to `ParenthesizedArgs` a `ThinVec` in the compiler --- compiler/rustc_ast/src/ast.rs | 4 +-- compiler/rustc_ast_lowering/src/path.rs | 4 +-- .../rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_parse/src/parser/path.rs | 30 ++++++++----------- compiler/rustc_parse/src/parser/ty.rs | 5 ++-- compiler/rustc_resolve/src/late.rs | 2 +- 7 files changed, 22 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f1ebc4292ee87..ee6150322a442 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -346,7 +346,7 @@ pub struct ParenthesizedArgs { pub span: Span, /// `(A, B)` - pub inputs: ThinVec>, + pub inputs: ThinVec, /// ```text /// Foo(A, B) -> C @@ -364,7 +364,7 @@ impl ParenthesizedArgs { .inputs .iter() .cloned() - .map(|input| AngleBracketedArg::Arg(GenericArg::Type(input))) + .map(|input| AngleBracketedArg::Arg(GenericArg::Type(input.ty))) .collect(); AngleBracketedArgs { span: self.inputs_span, args } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 8ac9654d4ba53..ae260c7d126ab 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -512,8 +512,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // compatibility, even in contexts like an impl header where // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; - let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { + self.lower_ty(¶m.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) })); let output_ty = match output { // Only allow `impl Trait` in return position. i.e.: diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index c630277dc77e2..f64d499d1bde0 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1771,7 +1771,7 @@ impl Visitor<'_> for AstValidator<'_> { } } GenericArgs::Parenthesized(data) => { - walk_list!(self, visit_ty, &data.inputs); + walk_list!(self, visit_param, &data.inputs); if let FnRetTy::Ty(ty) = &data.output { // `-> Foo` syntax is essentially an associated type binding, // so it is also allowed to contain nested `impl Trait`. diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 64c0be27a2daa..672ea9e5669f0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1212,7 +1212,7 @@ impl<'a> PrintState<'a> for State<'a> { ast::GenericArgs::Parenthesized(data) => { self.word("("); - self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty)); + self.commasep(Inconsistent, &data.inputs, |s, param| s.print_param(param, false)); self.word(")"); self.print_fn_ret_ty(&data.output); } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c1b7af997bf25..664c089e3f153 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -407,23 +407,19 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, false, false); - param.map(|param| { - if !matches!(param.pat.kind, PatKind::Missing) { - self.psess - .gated_spans - .gate(sym::named_fn_trait_parameters, param.pat.span); - } - if matches!(param.ty.kind, TyKind::CVarArgs) { - dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span }); - } - if !param.attrs.is_empty() { - dcx.emit_err(PathFoundAttributeInParams { - span: param.attrs[0].span, - }); - } - param.ty - }) + let param = p.parse_param_general(&mode, false, false)?; + if !matches!(param.pat.kind, PatKind::Missing) { + self.psess + .gated_spans + .gate(sym::named_fn_trait_parameters, param.pat.span); + } + if matches!(param.ty.kind, TyKind::CVarArgs) { + dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span }); + } + if !param.attrs.is_empty() { + dcx.emit_err(PathFoundAttributeInParams { span: param.attrs[0].span }); + } + Ok(param) }); let (inputs, _) = match parse_params_result { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index f93bc1639ffed..1d2021cfe50ae 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1451,7 +1451,7 @@ impl<'a> Parser<'a> { args: Some(Box::new(ast::GenericArgs::Parenthesized( ast::ParenthesizedArgs { span: args_lo.to(self.prev_token.span), - inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(), + inputs: decl.inputs.iter().map(|a| a.clone()).collect(), inputs_span: args_lo.until(decl.output.span()), output: decl.output.clone(), } @@ -1538,7 +1538,7 @@ impl<'a> Parser<'a> { let inputs_lo = self.token.span; let mode = FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false }; - let params = match self.parse_fn_params(&mode) { + let inputs = match self.parse_fn_params(&mode) { Ok(params) => params, Err(err) => { if let Some(snapshot) = snapshot { @@ -1550,7 +1550,6 @@ impl<'a> Parser<'a> { } } }; - let inputs: ThinVec<_> = params.into_iter().map(|input| input.ty).collect(); let inputs_span = inputs_lo.to(self.prev_token.span); let output = match self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 8b7c99e55edaa..0990bf73690ea 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1390,7 +1390,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.resolve_fn_signature( binder, false, - p_args.inputs.iter().map(|ty| (None, &**ty)), + p_args.inputs.iter().map(|param| (None, &*param.ty)), &p_args.output, false, ); From 8dac1c68ef1a56025f7f90101776cd5b869d8284 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 11 Aug 2026 20:48:12 +0200 Subject: [PATCH 2/4] Fix errors in tooling --- .../clippy/clippy_utils/src/ast_utils/mod.rs | 16 +++++++++------- .../clippy/clippy_utils/src/check_proc_macro.rs | 2 +- src/tools/rustfmt/src/types.rs | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 504a867335011..cdb21a8e7082f 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -107,7 +107,7 @@ fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { match (l, r) { (AngleBracketed(l), AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg), (Parenthesized(l), Parenthesized(r)) => { - over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output) + over(&l.inputs, &r.inputs, eq_param) && eq_fn_ret_ty(&l.output, &r.output) }, _ => false, } @@ -855,12 +855,14 @@ fn eq_restriction_kind(l: &RestrictionKind, r: &RestrictionKind) -> bool { fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool { eq_fn_ret_ty(&l.output, &r.output) - && over(&l.inputs, &r.inputs, |l, r| { - l.is_placeholder == r.is_placeholder - && eq_pat(&l.pat, &r.pat) - && eq_ty(&l.ty, &r.ty) - && over(&l.attrs, &r.attrs, eq_attr) - }) + && over(&l.inputs, &r.inputs, eq_param) +} + +fn eq_param(l: &Param, r: &Param) -> bool { + l.is_placeholder == r.is_placeholder + && eq_pat(&l.pat, &r.pat) + && eq_ty(&l.ty, &r.ty) + && over(&l.attrs, &r.attrs, eq_attr) } fn eq_closure_binder(l: &ClosureBinder, r: &ClosureBinder) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index efdaef24478ba..9f69c74596d50 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -486,7 +486,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { FnRetTy::Default(_) => { if let Some(last) = par_args.inputs.last() { // `B` in `(A, B)` -- `)` gets stripped - ast_ty_search_pat(last).1 + ast_ty_search_pat(&last.ty).1 } else { // `(` in `()` -- `)` gets stripped Pat::Str("(") diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index d6a25e61008f0..33898f49c5b1e 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -564,7 +564,7 @@ fn rewrite_generic_args( } } ast::GenericArgs::Parenthesized(ref data) => format_function_type( - data.inputs.iter().map(|x| &**x), + data.inputs.iter().map(|x| &*x.ty), &data.output, false, data.span, From bd5ccd32d2ee64d815ab9a3a99ef6a31856777a9 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 11 Aug 2026 20:56:04 +0200 Subject: [PATCH 3/4] Improve `rewrite_generic_args` to take pattern into account --- src/tools/rustfmt/src/types.rs | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 33898f49c5b1e..9edfa2cf438fe 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -313,19 +313,14 @@ fn rewrite_segment( Ok(result) } -fn format_function_type<'a, I>( - inputs: I, +fn format_function_type( + inputs: &[ast::Param], output: &FnRetTy, variadic: bool, span: Span, context: &RewriteContext<'_>, shape: Shape, -) -> RewriteResult -where - I: ExactSizeIterator, - ::Item: Deref, - ::Target: Rewrite + Spanned + 'a, -{ +) -> RewriteResult { debug!("format_function_type {:#?}", shape); let ty_shape = match context.config.indent_style() { @@ -381,7 +376,7 @@ where } else { let items = itemize_list( context.snippet_provider, - inputs, + inputs.iter(), ")", ",", |arg| arg.span().lo(), @@ -563,14 +558,9 @@ fn rewrite_generic_args( overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span) } } - ast::GenericArgs::Parenthesized(ref data) => format_function_type( - data.inputs.iter().map(|x| &*x.ty), - &data.output, - false, - data.span, - context, - shape, - ), + ast::GenericArgs::Parenthesized(ref data) => { + format_function_type(&data.inputs, &data.output, false, data.span, context, shape) + } ast::GenericArgs::ParenthesizedElided(..) => Ok("(..)".to_owned()), } } @@ -1129,7 +1119,7 @@ fn rewrite_fn_ptr( }; let rewrite = format_function_type( - fn_ptr.decl.inputs.iter(), + &fn_ptr.decl.inputs, &fn_ptr.decl.output, fn_ptr.decl.c_variadic(), span, From 2e637452fe77ff50307a2dc0633b1b006cde7a4b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 11 Aug 2026 21:12:31 +0200 Subject: [PATCH 4/4] Add rustfmt regression test --- .../tests/target/named-fn-trait-parameters.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/tools/rustfmt/tests/target/named-fn-trait-parameters.rs diff --git a/src/tools/rustfmt/tests/target/named-fn-trait-parameters.rs b/src/tools/rustfmt/tests/target/named-fn-trait-parameters.rs new file mode 100644 index 0000000000000..36621da20192f --- /dev/null +++ b/src/tools/rustfmt/tests/target/named-fn-trait-parameters.rs @@ -0,0 +1,15 @@ +fn allowed( + data: &str, + f1: impl Fn(msg: String), + f2: impl Fn(_: String), + f3: impl Fn(String, msg: String), + f4: impl Fn(msg: String, String), + fg: F, +) where + F: Fn(msg: String), +{ +} + +my_macro!(f(x: &str)); +my_macro!(f(x: &str) -> ()); +my_macro!(g(n: i32, m: usize) -> usize);