1 use crate::structured_errors::StructuredDiagnostic;
3 pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed,
7 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
8 use rustc_session::Session;
9 use rustc_span::def_id::DefId;
12 use GenericArgsInfo::*;
14 /// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
15 pub struct WrongNumberOfGenericArgs<'a, 'tcx> {
16 pub(crate) tcx: TyCtxt<'tcx>,
18 pub(crate) angle_brackets: AngleBrackets,
20 pub(crate) gen_args_info: GenericArgsInfo,
22 /// Offending path segment
23 pub(crate) path_segment: &'a hir::PathSegment<'a>,
25 /// Generic parameters as expected by type or trait
26 pub(crate) gen_params: &'a ty::Generics,
28 /// Index offset into parameters. Depends on whether `Self` is included and on
29 /// number of lifetime parameters in case we're processing missing or redundant
30 /// type or constant arguments.
31 pub(crate) params_offset: usize,
33 /// Generic arguments as provided by user
34 pub(crate) gen_args: &'a hir::GenericArgs<'a>,
36 /// DefId of the generic type
37 pub(crate) def_id: DefId,
40 // Provides information about the kind of arguments that were provided for
41 // the PathSegment, for which missing generic arguments were detected
43 pub(crate) enum AngleBrackets {
44 // No angle brackets were provided, but generic arguments exist in elided form
47 // No angle brackets were provided
50 // Angle brackets are available, but missing some generic arguments
54 // Information about the kind of arguments that are either missing or are unexpected
56 pub enum GenericArgsInfo {
58 num_missing_args: usize,
61 num_redundant_args: usize,
63 MissingTypesOrConsts {
64 num_missing_args: usize,
66 // type or const generic arguments can have default values
67 num_default_params: usize,
69 // lifetime arguments precede type and const parameters, this
70 // field gives the number of generic lifetime arguments to let
71 // us infer the position of type and const generic arguments
72 // in the angle brackets
77 num_redundant_args: usize,
79 // type or const generic arguments can have default values
80 num_default_params: usize,
82 // lifetime arguments precede type and const parameters, this
83 // field gives the number of generic lifetime arguments to let
84 // us infer the position of type and const generic arguments
85 // in the angle brackets
88 // if synthetic type arguments (e.g. `impl Trait`) are specified
93 impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
96 gen_args_info: GenericArgsInfo,
97 path_segment: &'a hir::PathSegment<'_>,
98 gen_params: &'a ty::Generics,
100 gen_args: &'a hir::GenericArgs<'a>,
103 let angle_brackets = if gen_args.span_ext().is_none() {
104 if gen_args.is_empty() { AngleBrackets::Missing } else { AngleBrackets::Implied }
106 AngleBrackets::Available
121 fn missing_lifetimes(&self) -> bool {
122 match self.gen_args_info {
123 MissingLifetimes { .. } | ExcessLifetimes { .. } => true,
124 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => false,
128 fn kind(&self) -> &str {
129 if self.missing_lifetimes() { "lifetime" } else { "generic" }
132 fn num_provided_args(&self) -> usize {
133 if self.missing_lifetimes() {
134 self.num_provided_lifetime_args()
136 self.num_provided_type_or_const_args()
140 fn num_provided_lifetime_args(&self) -> usize {
141 match self.angle_brackets {
142 AngleBrackets::Missing => 0,
143 // Only lifetime arguments can be implied
144 AngleBrackets::Implied => self.gen_args.args.len(),
145 AngleBrackets::Available => self.gen_args.num_lifetime_params(),
149 fn num_provided_type_or_const_args(&self) -> usize {
150 match self.angle_brackets {
151 AngleBrackets::Missing => 0,
152 // Only lifetime arguments can be implied
153 AngleBrackets::Implied => 0,
154 AngleBrackets::Available => self.gen_args.num_generic_params(),
158 fn num_expected_lifetime_args(&self) -> usize {
159 let num_provided_args = self.num_provided_lifetime_args();
160 match self.gen_args_info {
161 MissingLifetimes { num_missing_args } => num_provided_args + num_missing_args,
162 ExcessLifetimes { num_redundant_args } => num_provided_args - num_redundant_args,
167 fn num_expected_type_or_const_args(&self) -> usize {
168 let num_provided_args = self.num_provided_type_or_const_args();
169 match self.gen_args_info {
170 MissingTypesOrConsts { num_missing_args, .. } => num_provided_args + num_missing_args,
171 ExcessTypesOrConsts { num_redundant_args, .. } => {
172 num_provided_args - num_redundant_args
178 // Gives the number of expected arguments taking into account default arguments
179 fn num_expected_type_or_const_args_including_defaults(&self) -> usize {
180 let provided_args = self.num_provided_type_or_const_args();
181 match self.gen_args_info {
182 MissingTypesOrConsts { num_missing_args, num_default_params, .. } => {
183 provided_args + num_missing_args - num_default_params
185 ExcessTypesOrConsts { num_redundant_args, num_default_params, .. } => {
186 provided_args - num_redundant_args - num_default_params
192 fn num_missing_lifetime_args(&self) -> usize {
193 let missing_args = self.num_expected_lifetime_args() - self.num_provided_lifetime_args();
194 assert!(missing_args > 0);
198 fn num_missing_type_or_const_args(&self) -> usize {
199 let missing_args = self.num_expected_type_or_const_args_including_defaults()
200 - self.num_provided_type_or_const_args();
201 assert!(missing_args > 0);
205 fn num_excess_lifetime_args(&self) -> usize {
206 match self.gen_args_info {
207 ExcessLifetimes { num_redundant_args } => num_redundant_args,
212 fn num_excess_type_or_const_args(&self) -> usize {
213 match self.gen_args_info {
214 ExcessTypesOrConsts { num_redundant_args, .. } => num_redundant_args,
219 fn too_many_args_provided(&self) -> bool {
220 match self.gen_args_info {
221 MissingLifetimes { .. } | MissingTypesOrConsts { .. } => false,
222 ExcessLifetimes { num_redundant_args }
223 | ExcessTypesOrConsts { num_redundant_args, .. } => {
224 assert!(num_redundant_args > 0);
230 fn not_enough_args_provided(&self) -> bool {
231 match self.gen_args_info {
232 MissingLifetimes { num_missing_args }
233 | MissingTypesOrConsts { num_missing_args, .. } => {
234 assert!(num_missing_args > 0);
237 ExcessLifetimes { .. } | ExcessTypesOrConsts { .. } => false,
241 // Helper method to get the index offset in angle brackets, at which type or const arguments
243 fn get_lifetime_args_offset(&self) -> usize {
244 match self.gen_args_info {
245 MissingLifetimes { .. } | ExcessLifetimes { .. } => 0,
246 MissingTypesOrConsts { args_offset, .. } | ExcessTypesOrConsts { args_offset, .. } => {
252 fn get_num_default_params(&self) -> usize {
253 match self.gen_args_info {
254 MissingTypesOrConsts { num_default_params, .. }
255 | ExcessTypesOrConsts { num_default_params, .. } => num_default_params,
260 fn is_synth_provided(&self) -> bool {
261 match self.gen_args_info {
262 ExcessTypesOrConsts { synth_provided, .. } => synth_provided,
267 // Helper function to choose a quantifier word for the number of expected arguments
268 // and to give a bound for the number of expected arguments
269 fn get_quantifier_and_bound(&self) -> (&'static str, usize) {
270 if self.get_num_default_params() == 0 {
271 match self.gen_args_info {
272 MissingLifetimes { .. } | ExcessLifetimes { .. } => {
273 ("", self.num_expected_lifetime_args())
275 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => {
276 ("", self.num_expected_type_or_const_args())
280 match self.gen_args_info {
281 MissingLifetimes { .. } => ("at least ", self.num_expected_lifetime_args()),
282 MissingTypesOrConsts { .. } => {
283 ("at least ", self.num_expected_type_or_const_args_including_defaults())
285 ExcessLifetimes { .. } => ("at most ", self.num_expected_lifetime_args()),
286 ExcessTypesOrConsts { .. } => ("at most ", self.num_expected_type_or_const_args()),
291 // Creates lifetime name suggestions from the lifetime parameter names
292 fn get_lifetime_args_suggestions_from_param_names(
294 path_hir_id: hir::HirId,
295 num_params_to_take: usize,
297 debug!(?path_hir_id);
299 // If there was already a lifetime among the arguments, just replicate that one.
300 if let Some(lt) = self.gen_args.args.iter().find_map(|arg| match arg {
301 hir::GenericArg::Lifetime(lt) => Some(lt),
304 return std::iter::repeat(lt.to_string())
305 .take(num_params_to_take)
310 let mut ret = Vec::new();
311 let mut ty_id = None;
312 for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
314 if let hir::Node::Ty(_) = node {
318 // Suggest `'_` when in function parameter or elided function return.
319 if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id {
320 let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
321 let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
323 if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
324 return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", ");
328 // Suggest `'static` when in const/static item-like.
329 if let hir::Node::Item(hir::Item {
330 kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
333 | hir::Node::TraitItem(hir::TraitItem {
334 kind: hir::TraitItemKind::Const { .. },
337 | hir::Node::ImplItem(hir::ImplItem {
338 kind: hir::ImplItemKind::Const { .. },
341 | hir::Node::ForeignItem(hir::ForeignItem {
342 kind: hir::ForeignItemKind::Static { .. },
345 | hir::Node::AnonConst(..) = node
347 return std::iter::repeat("'static".to_owned())
348 .take(num_params_to_take.saturating_sub(ret.len()))
353 let params = if let Some(generics) = node.generics() {
355 } else if let hir::Node::Ty(ty) = node
356 && let hir::TyKind::BareFn(bare_fn) = ty.kind
358 bare_fn.generic_params
362 ret.extend(params.iter().filter_map(|p| {
363 let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
365 else { return None };
366 let hir::ParamName::Plain(name) = p.name else { return None };
367 Some(name.to_string())
370 if ret.len() >= num_params_to_take {
371 return ret[..num_params_to_take].join(", ");
373 // We cannot refer to lifetimes defined in an outer function.
374 if let hir::Node::Item(_) = node {
379 // We could not gather enough lifetime parameters in the scope.
380 // We use the parameter names from the target type's definition instead.
384 .skip(self.params_offset + self.num_provided_lifetime_args())
385 .take(num_params_to_take)
386 .map(|param| param.name.to_string())
391 // Creates type or constant name suggestions from the provided parameter names
392 fn get_type_or_const_args_suggestions_from_param_names(
394 num_params_to_take: usize,
396 let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig);
397 let is_used_in_input = |def_id| {
398 fn_sig.map_or(false, |fn_sig| {
399 fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
400 hir::TyKind::Path(hir::QPath::Resolved(
402 hir::Path { res: hir::def::Res::Def(_, id), .. },
411 .skip(self.params_offset + self.num_provided_type_or_const_args())
412 .take(num_params_to_take)
413 .map(|param| match param.kind {
414 // This is being inferred from the item's inputs, no need to set it.
415 ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
418 _ => param.name.to_string(),
424 fn get_unbound_associated_types(&self) -> Vec<String> {
425 if self.tcx.is_trait(self.def_id) {
426 let items: &AssocItems<'_> = self.tcx.associated_items(self.def_id);
428 .in_definition_order()
429 .filter(|item| item.kind == AssocKind::Type)
431 !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
433 .map(|item| item.name.to_ident_string())
440 fn create_error_message(&self) -> String {
441 let def_path = self.tcx.def_path_str(self.def_id);
442 let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
443 let (quantifier, bound) = self.get_quantifier_and_bound();
444 let kind = self.kind();
445 let provided_lt_args = self.num_provided_lifetime_args();
446 let provided_type_or_const_args = self.num_provided_type_or_const_args();
448 let (provided_args_str, verb) = match self.gen_args_info {
449 MissingLifetimes { .. } | ExcessLifetimes { .. } => (
450 format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)),
451 pluralize!("was", provided_lt_args),
453 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => (
455 "{} generic argument{}",
456 provided_type_or_const_args,
457 pluralize!(provided_type_or_const_args)
459 pluralize!("was", provided_type_or_const_args),
463 if self.gen_args.span_ext().is_some() {
465 "this {} takes {}{} {} argument{} but {} {} supplied",
471 provided_args_str.as_str(),
475 format!("missing generics for {} `{}`", def_kind, def_path)
479 fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
480 let span = self.path_segment.ident.span;
481 let msg = self.create_error_message();
483 self.tcx.sess.struct_span_err_with_code(span, &msg, self.code())
486 /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
487 fn notify(&self, err: &mut Diagnostic) {
488 let (quantifier, bound) = self.get_quantifier_and_bound();
489 let provided_args = self.num_provided_args();
492 self.path_segment.ident.span,
494 "expected {}{} {} argument{}",
502 // When too many arguments were provided, we don't highlight each of them, because it
503 // would overlap with the suggestion to remove them:
506 // type Foo = Bar<usize, usize>;
507 // ----- ----- supplied 2 type arguments
508 // ^^^^^^^ remove this type argument
510 if self.too_many_args_provided() {
518 .skip(self.get_lifetime_args_offset())
522 for (i, arg) in args {
525 if i + 1 == provided_args {
527 "supplied {} {} argument{}",
530 pluralize!(provided_args)
539 fn suggest(&self, err: &mut Diagnostic) {
541 "suggest(self.provided {:?}, self.gen_args.span(): {:?})",
542 self.num_provided_args(),
543 self.gen_args.span(),
546 match self.angle_brackets {
547 AngleBrackets::Missing | AngleBrackets::Implied => self.suggest_adding_args(err),
548 AngleBrackets::Available => {
549 if self.not_enough_args_provided() {
550 self.suggest_adding_args(err);
551 } else if self.too_many_args_provided() {
552 self.suggest_moving_args_from_assoc_fn_to_trait(err);
553 self.suggest_removing_args_or_generics(err);
561 /// Suggests to add missing argument(s) when current invocation site already contains some
565 /// type Map = HashMap<String>;
567 fn suggest_adding_args(&self, err: &mut Diagnostic) {
568 if self.gen_args.parenthesized {
572 match self.gen_args_info {
573 MissingLifetimes { .. } => {
574 self.suggest_adding_lifetime_args(err);
576 MissingTypesOrConsts { .. } => {
577 self.suggest_adding_type_and_const_args(err);
583 fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) {
584 debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment);
585 let num_missing_args = self.num_missing_lifetime_args();
586 let num_params_to_take = num_missing_args;
587 let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
589 let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
590 self.path_segment.hir_id,
593 debug!("suggested_args: {:?}", &suggested_args);
595 match self.angle_brackets {
596 AngleBrackets::Missing => {
597 let span = self.path_segment.ident.span;
599 // insert a suggestion of the form "Y<'a, 'b>"
600 let ident = self.path_segment.ident.name.to_ident_string();
601 let sugg = format!("{}<{}>", ident, suggested_args);
602 debug!("sugg: {:?}", sugg);
604 err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
607 AngleBrackets::Available => {
608 let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 {
609 (self.gen_args.span().unwrap().shrink_to_lo(), true)
611 let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1];
612 (last_lt.span().shrink_to_hi(), false)
614 let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
615 let has_bindings = !self.gen_args.bindings.is_empty();
617 let sugg_prefix = if is_first { "" } else { ", " };
619 if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" };
621 let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
622 debug!("sugg: {:?}", sugg);
624 err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
626 AngleBrackets::Implied => {
627 // We never encounter missing lifetimes in situations in which lifetimes are elided
633 fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
634 let num_missing_args = self.num_missing_type_or_const_args();
635 let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
638 self.get_type_or_const_args_suggestions_from_param_names(num_missing_args);
639 debug!("suggested_args: {:?}", suggested_args);
641 match self.angle_brackets {
642 AngleBrackets::Missing | AngleBrackets::Implied => {
643 let span = self.path_segment.ident.span;
645 // insert a suggestion of the form "Y<T, U>"
646 let ident = self.path_segment.ident.name.to_ident_string();
647 let sugg = format!("{}<{}>", ident, suggested_args);
648 debug!("sugg: {:?}", sugg);
650 err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
652 AngleBrackets::Available => {
653 let gen_args_span = self.gen_args.span().unwrap();
655 self.get_lifetime_args_offset() + self.num_provided_type_or_const_args();
657 let (sugg_span, is_first) = if sugg_offset == 0 {
658 (gen_args_span.shrink_to_lo(), true)
660 let arg_span = self.gen_args.args[sugg_offset - 1].span();
661 // If we came here then inferred lifetime's spans can only point
662 // to either the opening bracket or to the space right after.
663 // Both of these spans have an `hi` lower than or equal to the span
664 // of the generics excluding the brackets.
665 // This allows us to check if `arg_span` is the artificial span of
666 // an inferred lifetime, in which case the generic we're suggesting to
667 // add will be the first visible, even if it isn't the actual first generic.
668 (arg_span.shrink_to_hi(), arg_span.hi() <= gen_args_span.lo())
671 let sugg_prefix = if is_first { "" } else { ", " };
673 if is_first && !self.gen_args.bindings.is_empty() { ", " } else { "" };
675 let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
676 debug!("sugg: {:?}", sugg);
678 err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
683 /// Suggests moving redundant argument(s) of an associate function to the
684 /// trait it belongs to.
687 /// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
689 fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) {
690 let trait_ = match self.tcx.trait_of_item(self.def_id) {
691 Some(def_id) => def_id,
695 // Skip suggestion when the associated function is itself generic, it is unclear
696 // how to split the provided parameters between those to suggest to the trait and
697 // those to remain on the associated type.
698 let num_assoc_fn_expected_args =
699 self.num_expected_type_or_const_args() + self.num_expected_lifetime_args();
700 if num_assoc_fn_expected_args > 0 {
704 let num_assoc_fn_excess_args =
705 self.num_excess_type_or_const_args() + self.num_excess_lifetime_args();
707 let trait_generics = self.tcx.generics_of(trait_);
708 let num_trait_generics_except_self =
709 trait_generics.count() - if trait_generics.has_self { 1 } else { 0 };
712 "consider moving {these} generic argument{s} to the `{name}` trait, which takes up to {num} argument{s}",
713 these = pluralize!("this", num_assoc_fn_excess_args),
714 s = pluralize!(num_assoc_fn_excess_args),
715 name = self.tcx.item_name(trait_),
716 num = num_trait_generics_except_self,
719 if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id)
720 && let Some(parent_node) = self.tcx.hir().find(parent_node)
721 && let hir::Node::Expr(expr) = parent_node {
723 hir::ExprKind::Path(ref qpath) => {
724 self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
728 num_assoc_fn_excess_args,
729 num_trait_generics_except_self
732 hir::ExprKind::MethodCall(..) => {
733 self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
738 num_assoc_fn_excess_args,
739 num_trait_generics_except_self
747 fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
749 err: &mut Diagnostic,
750 qpath: &'tcx hir::QPath<'tcx>,
752 num_assoc_fn_excess_args: usize,
753 num_trait_generics_except_self: usize,
755 if let hir::QPath::Resolved(_, path) = qpath
756 && let Some(trait_path_segment) = path.segments.get(0) {
757 let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
759 if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self
761 if let Some(span) = self.gen_args.span_ext()
762 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
764 (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)),
765 (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned())
768 err.multipart_suggestion(
771 Applicability::MaybeIncorrect
778 fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
780 err: &mut Diagnostic,
782 expr: &'tcx hir::Expr<'tcx>,
784 num_assoc_fn_excess_args: usize,
785 num_trait_generics_except_self: usize,
787 let sm = self.tcx.sess.source_map();
788 let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return; };
789 if num_assoc_fn_excess_args != num_trait_generics_except_self {
792 let Some(gen_args) = self.gen_args.span_ext() else { return; };
793 let Ok(generics) = sm.span_to_snippet(gen_args) else { return; };
794 let Ok(rcvr) = sm.span_to_snippet(
795 rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span)
799 [] => Ok(String::new()),
800 [arg] => sm.span_to_snippet(
801 arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span),
803 [first, .., last] => {
805 first.span.find_ancestor_inside(expr.span).unwrap_or(first.span);
807 last.span.find_ancestor_inside(expr.span).unwrap_or(last.span);
808 sm.span_to_snippet(first_span.to(last_span))
811 let comma = if args.len() > 0 { ", " } else { "" };
812 let trait_path = self.tcx.def_path_str(trait_def_id);
813 let method_name = self.tcx.item_name(self.def_id);
817 format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"),
818 Applicability::MaybeIncorrect,
822 /// Suggests to remove redundant argument(s):
825 /// type Map = HashMap<String, String, String, String>;
827 fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
828 let num_provided_lt_args = self.num_provided_lifetime_args();
829 let num_provided_type_const_args = self.num_provided_type_or_const_args();
830 let unbound_types = self.get_unbound_associated_types();
831 let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
832 assert!(num_provided_args > 0);
834 let num_redundant_lt_args = self.num_excess_lifetime_args();
835 let num_redundant_type_or_const_args = self.num_excess_type_or_const_args();
836 let num_redundant_args = num_redundant_lt_args + num_redundant_type_or_const_args;
838 let redundant_lifetime_args = num_redundant_lt_args > 0;
839 let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
841 let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
842 let provided_args_matches_unbound_traits =
843 unbound_types.len() == num_redundant_type_or_const_args;
845 let remove_lifetime_args = |err: &mut Diagnostic| {
846 let mut lt_arg_spans = Vec::new();
847 let mut found_redundant = false;
848 for arg in self.gen_args.args {
849 if let hir::GenericArg::Lifetime(_) = arg {
850 lt_arg_spans.push(arg.span());
851 if lt_arg_spans.len() > self.num_expected_lifetime_args() {
852 found_redundant = true;
854 } else if found_redundant {
855 // Argument which is redundant and separated like this `'c`
856 // is not included to avoid including `Bar` in span.
858 // type Foo<'a, T> = &'a T;
859 // let _: Foo<'a, 'b, Bar, 'c>;
865 let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
866 let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
868 let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
869 debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
871 let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
872 let msg_lifetimes = format!(
873 "remove {these} lifetime argument{s}",
874 these = pluralize!("this", num_redundant_lt_args),
875 s = pluralize!(num_redundant_lt_args),
879 span_redundant_lt_args,
882 Applicability::MaybeIncorrect,
886 let remove_type_or_const_args = |err: &mut Diagnostic| {
887 let mut gen_arg_spans = Vec::new();
888 let mut found_redundant = false;
889 for arg in self.gen_args.args {
891 hir::GenericArg::Type(_)
892 | hir::GenericArg::Const(_)
893 | hir::GenericArg::Infer(_) => {
894 gen_arg_spans.push(arg.span());
895 if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
896 found_redundant = true;
899 _ if found_redundant => break,
904 let span_lo_redundant_type_or_const_args =
905 gen_arg_spans[self.num_expected_type_or_const_args()];
906 let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
908 let span_redundant_type_or_const_args =
909 span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
910 debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
912 let num_redundant_gen_args =
913 gen_arg_spans.len() - self.num_expected_type_or_const_args();
914 let msg_types_or_consts = format!(
915 "remove {these} generic argument{s}",
916 these = pluralize!("this", num_redundant_gen_args),
917 s = pluralize!(num_redundant_gen_args),
921 span_redundant_type_or_const_args,
922 &msg_types_or_consts,
924 Applicability::MaybeIncorrect,
928 // If there is a single unbound associated type and a single excess generic param
929 // suggest replacing the generic param with the associated type bound
930 if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
931 let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
932 let suggestions = iter::zip(unused_generics, &unbound_types)
933 .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
934 .collect::<Vec<_>>();
936 if !suggestions.is_empty() {
937 err.multipart_suggestion_verbose(
939 "replace the generic bound{s} with the associated type{s}",
940 s = pluralize!(unbound_types.len())
943 Applicability::MaybeIncorrect,
946 } else if remove_entire_generics {
953 .with_lo(self.path_segment.ident.span.hi());
956 "remove these {}generics",
957 if self.gen_args.parenthesized { "parenthetical " } else { "" },
960 err.span_suggestion(span, &msg, "", Applicability::MaybeIncorrect);
961 } else if redundant_lifetime_args && redundant_type_or_const_args {
962 remove_lifetime_args(err);
963 remove_type_or_const_args(err);
964 } else if redundant_lifetime_args {
965 remove_lifetime_args(err);
967 assert!(redundant_type_or_const_args);
968 remove_type_or_const_args(err);
972 /// Builds the `type defined here` message.
973 fn show_definition(&self, err: &mut Diagnostic) {
974 let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
975 if self.tcx.sess.source_map().is_span_accessible(def_span) {
985 let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
986 let (quantifier, bound) = self.get_quantifier_and_bound();
988 let params = if bound == 0 {
995 .skip(self.params_offset)
998 let span = self.tcx.def_span(param.def_id);
999 spans.push_span_label(span, "");
1002 .map(|param| format!("`{}`", param.name))
1003 .collect::<Vec<_>>()
1006 format!(": {}", params)
1010 "{} defined here, with {}{} {} parameter{}{}",
1020 err.span_note(spans, &msg);
1023 /// Add note if `impl Trait` is explicitly specified.
1024 fn note_synth_provided(&self, err: &mut Diagnostic) {
1025 if !self.is_synth_provided() {
1029 err.note("`impl Trait` cannot be explicitly specified as a generic argument");
1033 impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
1034 fn session(&self) -> &Session {
1038 fn code(&self) -> DiagnosticId {
1039 rustc_errors::error_code!(E0107)
1042 fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
1043 let mut err = self.start_diagnostics();
1045 self.notify(&mut err);
1046 self.suggest(&mut err);
1047 self.show_definition(&mut err);
1048 self.note_synth_provided(&mut err);