From c1f6331d1341a41a58d7d0acd7a9df0574efc388 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 15 Jun 2026 09:13:44 +0000 Subject: [PATCH] add suggestion for mgca to add assoc type --- .../wrong_number_of_generic_args.rs | 46 ++++++++++++------- .../const-generics/issues/issue-87493.stderr | 4 -- .../mgca/type-const-suggestion.rs | 11 +++++ .../mgca/type-const-suggestion.stderr | 19 ++++++++ tests/ui/error-codes/E0107.rs | 2 +- tests/ui/error-codes/E0107.stderr | 2 +- ...use-type-argument-instead-of-assoc-type.rs | 4 +- ...type-argument-instead-of-assoc-type.stderr | 14 ++++-- ...assoc-type-suggestion-in-trait-impl.stderr | 12 ++--- ..._mismatch_in_unsatisfied_projection.stderr | 2 +- 10 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 tests/ui/const-generics/mgca/type-const-suggestion.rs create mode 100644 tests/ui/const-generics/mgca/type-const-suggestion.stderr diff --git a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs index 4067161d93d72..c80c63b7c0188 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs @@ -1,10 +1,8 @@ -use std::iter; - use GenericArgsInfo::*; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir as hir; -use rustc_middle::ty::{self as ty, AssocItems, TyCtxt}; +use rustc_middle::ty::{self as ty, AssocItem, AssocItems, TyCtxt}; use rustc_span::def_id::DefId; use tracing::debug; @@ -485,13 +483,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .collect() } - fn get_unbound_associated_types(&self) -> Vec { + fn get_unbound_associated_item(&self) -> Vec<&AssocItem> { if self.tcx.is_trait(self.def_id) { let items: &AssocItems = self.tcx.associated_items(self.def_id); items .in_definition_order() .filter(|item| { - item.is_type() + (item.is_type() || item.is_type_const()) && !item.is_impl_trait_in_trait() && !self .gen_args @@ -499,7 +497,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .iter() .any(|constraint| constraint.ident.name == item.name()) }) - .map(|item| self.tcx.item_ident(item.def_id).to_string()) .collect() } else { Vec::default() @@ -905,7 +902,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); - let unbound_types = self.get_unbound_associated_types(); + let unbound_assoc_items = self.get_unbound_associated_item(); let num_provided_args = num_provided_lt_args + num_provided_type_const_args; assert!(num_provided_args > 0); @@ -917,8 +914,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let redundant_type_or_const_args = num_redundant_type_or_const_args > 0; let remove_entire_generics = num_redundant_args >= self.gen_args.args.len(); - let provided_args_matches_unbound_traits = - unbound_types.len() == num_redundant_type_or_const_args; let remove_lifetime_args = |err: &mut Diag<'_, _>| { let mut lt_arg_spans = Vec::new(); @@ -1012,24 +1007,41 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); }; - // If there is a single unbound associated type and a single excess generic param - // suggest replacing the generic param with the associated type bound - if provided_args_matches_unbound_traits && !unbound_types.is_empty() { + // If there is an identical amount of unbound associated items and excess generic args + // suggest turning the generic args into associated item bindings + if unbound_assoc_items.len() == num_redundant_type_or_const_args + && !unbound_assoc_items.is_empty() + { // Don't suggest if we're in a trait impl as // that would result in invalid syntax (fixes #116464) if !self.is_in_trait_impl() { let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; - let suggestions = iter::zip(unused_generics, &unbound_types) - .map(|(potential, name)| { - (potential.span().shrink_to_lo(), format!("{name} = ")) + let mut unbound_assoc_consts = + unbound_assoc_items.iter().filter(|item| item.is_type_const()); + let mut unbound_assoc_types = + unbound_assoc_items.iter().filter(|item| item.is_type()); + let suggestions = unused_generics + .iter() + .filter_map(|potential| { + let item = match potential { + hir::GenericArg::Const(_) => unbound_assoc_consts.next(), + hir::GenericArg::Type(_) => unbound_assoc_types.next(), + _ => None, + }?; + Some(( + potential.span().shrink_to_lo(), + // FIXME: This doesn't account for generic associated items + format!("{} = ", self.tcx.item_ident(item.def_id)), + )) }) .collect::>(); if !suggestions.is_empty() { + let s = pluralize!(suggestions.len()); + let article = if suggestions.len() == 1 { "an " } else { "" }; err.multipart_suggestion( format!( - "replace the generic bound{s} with the associated type{s}", - s = pluralize!(unbound_types.len()) + "turn the generic argument{s} into {article}associated item binding{s}" ), suggestions, Applicability::MaybeIncorrect, diff --git a/tests/ui/const-generics/issues/issue-87493.stderr b/tests/ui/const-generics/issues/issue-87493.stderr index 42d32a0ee0502..8ab5289ac73b0 100644 --- a/tests/ui/const-generics/issues/issue-87493.stderr +++ b/tests/ui/const-generics/issues/issue-87493.stderr @@ -21,10 +21,6 @@ note: trait defined here, with 0 generic parameters | LL | pub trait MyTrait { | ^^^^^^^ -help: replace the generic bound with the associated type - | -LL | T: MyTrait, - | +++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/type-const-suggestion.rs b/tests/ui/const-generics/mgca/type-const-suggestion.rs new file mode 100644 index 0000000000000..8b01f17d41d9e --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-suggestion.rs @@ -0,0 +1,11 @@ +//! Regression test for . + +#![feature(min_generic_const_args)] + +trait Trait { + type const K: i32; +} +fn take(_: impl Trait<0>) {} +//~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied [E0107] + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type-const-suggestion.stderr b/tests/ui/const-generics/mgca/type-const-suggestion.stderr new file mode 100644 index 0000000000000..d59dc60ebca1c --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-suggestion.stderr @@ -0,0 +1,19 @@ +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/type-const-suggestion.rs:8:17 + | +LL | fn take(_: impl Trait<0>) {} + | ^^^^^ expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/type-const-suggestion.rs:5:7 + | +LL | trait Trait { + | ^^^^^ +help: turn the generic argument into an associated item binding + | +LL | fn take(_: impl Trait) {} + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/error-codes/E0107.rs b/tests/ui/error-codes/E0107.rs index 161360a501285..f23c594ab80ba 100644 --- a/tests/ui/error-codes/E0107.rs +++ b/tests/ui/error-codes/E0107.rs @@ -54,7 +54,7 @@ pub trait T { fn trait_bound_generic>(_i: I) { //~^ ERROR trait takes 0 generic arguments - //~| HELP replace the generic bounds with the associated types + //~| HELP turn the generic arguments into associated item bindings } fn main() {} diff --git a/tests/ui/error-codes/E0107.stderr b/tests/ui/error-codes/E0107.stderr index 4aa83cf7f5ff4..21f741e41086c 100644 --- a/tests/ui/error-codes/E0107.stderr +++ b/tests/ui/error-codes/E0107.stderr @@ -139,7 +139,7 @@ note: trait defined here, with 0 generic parameters | LL | pub trait T { | ^ -help: replace the generic bounds with the associated types +help: turn the generic arguments into associated item bindings | LL | fn trait_bound_generic>(_i: I) { | +++ +++ diff --git a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs index c2387bf5411d1..a97b1491857f5 100644 --- a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs +++ b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs @@ -4,9 +4,11 @@ pub trait T { type C; } pub struct Foo { - i: Box>, + i: Box>, //~^ ERROR trait takes 2 generic arguments but 4 generic arguments were supplied } +fn take(_: impl Iterator<0>) {} +//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied fn main() {} diff --git a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 18cf0674f0231..8f49eb55d11e1 100644 --- a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -1,7 +1,7 @@ error[E0107]: trait takes 2 generic arguments but 4 generic arguments were supplied --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16 | -LL | i: Box>, +LL | i: Box>, | ^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `X`, `Y` @@ -9,11 +9,17 @@ note: trait defined here, with 2 generic parameters: `X`, `Y` | LL | pub trait T { | ^ - - -help: replace the generic bounds with the associated types +help: turn the generic arguments into associated item bindings | -LL | i: Box>, +LL | i: Box>, | +++ +++ -error: aborting due to 1 previous error +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/use-type-argument-instead-of-assoc-type.rs:11:17 + | +LL | fn take(_: impl Iterator<0>) {} + | ^^^^^^^^ expected 0 generic arguments + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr index 54c0cf8ebee91..0c045660cf7c2 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -27,7 +27,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | fn func>(t: T) -> impl Trait<(), i32> { | +++++++ @@ -43,7 +43,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ @@ -59,7 +59,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | struct Struct> { | +++++++ @@ -75,7 +75,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | trait AnotherTrait> {} | +++++++ @@ -91,7 +91,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | impl> Struct {} | +++++++ @@ -122,7 +122,7 @@ note: trait defined here, with 1 generic parameter: `T` LL | pub trait Trait { | ^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ diff --git a/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr index acda3418894d6..e02bb32c13c0c 100644 --- a/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr +++ b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr @@ -9,7 +9,7 @@ note: trait defined here, with 0 generic parameters | LL | trait Output<'a> { | ^^^^^^ -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | F: for<'a> FnOnce(>::Type), | ++++++