1use std::iter;
2
3use GenericArgsInfo::*;
4use rustc_errors::codes::*;
5use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
6use rustc_hir as hir;
7use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
8use rustc_span::def_id::DefId;
9use tracing::debug;
10
11pub(crate) struct WrongNumberOfGenericArgs<'a, 'tcx> {
13 pub(crate) tcx: TyCtxt<'tcx>,
14
15 pub(crate) angle_brackets: AngleBrackets,
16
17 pub(crate) gen_args_info: GenericArgsInfo,
18
19 pub(crate) path_segment: &'a hir::PathSegment<'a>,
21
22 pub(crate) gen_params: &'a ty::Generics,
24
25 pub(crate) params_offset: usize,
29
30 pub(crate) gen_args: &'a hir::GenericArgs<'a>,
32
33 pub(crate) def_id: DefId,
35}
36
37#[derive(Debug)]
40pub(crate) enum AngleBrackets {
41 Implied,
43
44 Missing,
46
47 Available,
49}
50
51#[derive(Debug)]
53pub(crate) enum GenericArgsInfo {
54 MissingLifetimes {
55 num_missing_args: usize,
56 },
57 ExcessLifetimes {
58 num_redundant_args: usize,
59 },
60 MissingTypesOrConsts {
61 num_missing_args: usize,
62
63 num_default_params: usize,
65
66 args_offset: usize,
71 },
72
73 ExcessTypesOrConsts {
74 num_redundant_args: usize,
75
76 num_default_params: usize,
78
79 args_offset: usize,
84
85 synth_provided: bool,
87 },
88}
89
90impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
91 pub(crate) fn new(
92 tcx: TyCtxt<'tcx>,
93 gen_args_info: GenericArgsInfo,
94 path_segment: &'a hir::PathSegment<'_>,
95 gen_params: &'a ty::Generics,
96 params_offset: usize,
97 gen_args: &'a hir::GenericArgs<'a>,
98 def_id: DefId,
99 ) -> Self {
100 let angle_brackets = if gen_args.span_ext().is_none() {
101 if gen_args.is_empty() { AngleBrackets::Missing } else { AngleBrackets::Implied }
102 } else {
103 AngleBrackets::Available
104 };
105
106 Self {
107 tcx,
108 angle_brackets,
109 gen_args_info,
110 path_segment,
111 gen_params,
112 params_offset,
113 gen_args,
114 def_id,
115 }
116 }
117
118 fn missing_lifetimes(&self) -> bool {
119 match self.gen_args_info {
120 MissingLifetimes { .. } | ExcessLifetimes { .. } => true,
121 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => false,
122 }
123 }
124
125 fn kind(&self) -> &str {
126 if self.missing_lifetimes() { "lifetime" } else { "generic" }
127 }
128
129 fn is_in_trait_impl(&self) -> bool {
132 if self.tcx.is_trait(self.def_id) {
133 let parent = self.tcx.parent_hir_node(self.path_segment.hir_id);
137 let parent_item = self.tcx.hir_node_by_def_id(
138 self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id,
139 );
140
141 let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
143 return false;
144 };
145
146 let hir::Node::Item(hir::Item {
148 kind:
149 hir::ItemKind::Impl(hir::Impl {
150 of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
151 ..
152 }),
153 ..
154 }) = parent_item
155 else {
156 return false;
157 };
158
159 trait_ref_id == id_in_of_trait
161 } else {
162 false
163 }
164 }
165
166 fn num_provided_args(&self) -> usize {
167 if self.missing_lifetimes() {
168 self.num_provided_lifetime_args()
169 } else {
170 self.num_provided_type_or_const_args()
171 }
172 }
173
174 fn num_provided_lifetime_args(&self) -> usize {
175 match self.angle_brackets {
176 AngleBrackets::Missing => 0,
177 AngleBrackets::Implied => self.gen_args.args.len(),
179 AngleBrackets::Available => self.gen_args.num_lifetime_params(),
180 }
181 }
182
183 fn num_provided_type_or_const_args(&self) -> usize {
184 match self.angle_brackets {
185 AngleBrackets::Missing => 0,
186 AngleBrackets::Implied => 0,
188 AngleBrackets::Available => self.gen_args.num_generic_params(),
189 }
190 }
191
192 fn num_expected_lifetime_args(&self) -> usize {
193 let num_provided_args = self.num_provided_lifetime_args();
194 match self.gen_args_info {
195 MissingLifetimes { num_missing_args } => num_provided_args + num_missing_args,
196 ExcessLifetimes { num_redundant_args } => num_provided_args - num_redundant_args,
197 _ => 0,
198 }
199 }
200
201 fn num_expected_type_or_const_args(&self) -> usize {
202 let num_provided_args = self.num_provided_type_or_const_args();
203 match self.gen_args_info {
204 MissingTypesOrConsts { num_missing_args, .. } => num_provided_args + num_missing_args,
205 ExcessTypesOrConsts { num_redundant_args, .. } => {
206 num_provided_args - num_redundant_args
207 }
208 _ => 0,
209 }
210 }
211
212 fn num_expected_type_or_const_args_including_defaults(&self) -> usize {
214 let provided_args = self.num_provided_type_or_const_args();
215 match self.gen_args_info {
216 MissingTypesOrConsts { num_missing_args, num_default_params, .. } => {
217 provided_args + num_missing_args - num_default_params
218 }
219 ExcessTypesOrConsts { num_redundant_args, num_default_params, .. } => {
220 provided_args - num_redundant_args - num_default_params
221 }
222 _ => 0,
223 }
224 }
225
226 fn num_missing_lifetime_args(&self) -> usize {
227 let missing_args = self.num_expected_lifetime_args() - self.num_provided_lifetime_args();
228 assert!(missing_args > 0);
229 missing_args
230 }
231
232 fn num_missing_type_or_const_args(&self) -> usize {
233 let missing_args = self.num_expected_type_or_const_args_including_defaults()
234 - self.num_provided_type_or_const_args();
235 assert!(missing_args > 0);
236 missing_args
237 }
238
239 fn num_excess_lifetime_args(&self) -> usize {
240 match self.gen_args_info {
241 ExcessLifetimes { num_redundant_args } => num_redundant_args,
242 _ => 0,
243 }
244 }
245
246 fn num_excess_type_or_const_args(&self) -> usize {
247 match self.gen_args_info {
248 ExcessTypesOrConsts { num_redundant_args, .. } => num_redundant_args,
249 _ => 0,
250 }
251 }
252
253 fn too_many_args_provided(&self) -> bool {
254 match self.gen_args_info {
255 MissingLifetimes { .. } | MissingTypesOrConsts { .. } => false,
256 ExcessLifetimes { num_redundant_args }
257 | ExcessTypesOrConsts { num_redundant_args, .. } => {
258 assert!(num_redundant_args > 0);
259 true
260 }
261 }
262 }
263
264 fn not_enough_args_provided(&self) -> bool {
265 match self.gen_args_info {
266 MissingLifetimes { num_missing_args }
267 | MissingTypesOrConsts { num_missing_args, .. } => {
268 assert!(num_missing_args > 0);
269 true
270 }
271 ExcessLifetimes { .. } | ExcessTypesOrConsts { .. } => false,
272 }
273 }
274
275 fn get_lifetime_args_offset(&self) -> usize {
278 match self.gen_args_info {
279 MissingLifetimes { .. } | ExcessLifetimes { .. } => 0,
280 MissingTypesOrConsts { args_offset, .. } | ExcessTypesOrConsts { args_offset, .. } => {
281 args_offset
282 }
283 }
284 }
285
286 fn get_num_default_params(&self) -> usize {
287 match self.gen_args_info {
288 MissingTypesOrConsts { num_default_params, .. }
289 | ExcessTypesOrConsts { num_default_params, .. } => num_default_params,
290 _ => 0,
291 }
292 }
293
294 fn is_synth_provided(&self) -> bool {
295 match self.gen_args_info {
296 ExcessTypesOrConsts { synth_provided, .. } => synth_provided,
297 _ => false,
298 }
299 }
300
301 fn get_quantifier_and_bound(&self) -> (&'static str, usize) {
304 if self.get_num_default_params() == 0 {
305 match self.gen_args_info {
306 MissingLifetimes { .. } | ExcessLifetimes { .. } => {
307 ("", self.num_expected_lifetime_args())
308 }
309 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => {
310 ("", self.num_expected_type_or_const_args())
311 }
312 }
313 } else {
314 match self.gen_args_info {
315 MissingLifetimes { .. } => ("at least ", self.num_expected_lifetime_args()),
316 MissingTypesOrConsts { .. } => {
317 ("at least ", self.num_expected_type_or_const_args_including_defaults())
318 }
319 ExcessLifetimes { .. } => ("at most ", self.num_expected_lifetime_args()),
320 ExcessTypesOrConsts { .. } => ("at most ", self.num_expected_type_or_const_args()),
321 }
322 }
323 }
324
325 fn get_lifetime_args_suggestions_from_param_names(
327 &self,
328 path_hir_id: hir::HirId,
329 num_params_to_take: usize,
330 ) -> String {
331 debug!(?path_hir_id);
332
333 if let Some(lt) = self.gen_args.args.iter().find_map(|arg| match arg {
335 hir::GenericArg::Lifetime(lt) => Some(lt),
336 _ => None,
337 }) {
338 return std::iter::repeat(lt.to_string())
339 .take(num_params_to_take)
340 .collect::<Vec<_>>()
341 .join(", ");
342 }
343
344 let mut ret = Vec::new();
345 let mut ty_id = None;
346 for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
347 debug!(?id);
348 if let hir::Node::Ty(_) = node {
349 ty_id = Some(id);
350 }
351
352 if let Some(fn_decl) = node.fn_decl()
354 && let Some(ty_id) = ty_id
355 {
356 let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
357 let in_ret =
358 matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
359
360 if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
361 return std::iter::repeat("'_".to_owned())
362 .take(num_params_to_take)
363 .collect::<Vec<_>>()
364 .join(", ");
365 }
366 }
367
368 if let hir::Node::Item(hir::Item {
370 kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
371 ..
372 })
373 | hir::Node::TraitItem(hir::TraitItem {
374 kind: hir::TraitItemKind::Const { .. },
375 ..
376 })
377 | hir::Node::ImplItem(hir::ImplItem {
378 kind: hir::ImplItemKind::Const { .. },
379 ..
380 })
381 | hir::Node::ForeignItem(hir::ForeignItem {
382 kind: hir::ForeignItemKind::Static { .. },
383 ..
384 })
385 | hir::Node::AnonConst(..) = node
386 {
387 return std::iter::repeat("'static".to_owned())
388 .take(num_params_to_take.saturating_sub(ret.len()))
389 .collect::<Vec<_>>()
390 .join(", ");
391 }
392
393 let params = if let Some(generics) = node.generics() {
394 generics.params
395 } else if let hir::Node::Ty(ty) = node
396 && let hir::TyKind::BareFn(bare_fn) = ty.kind
397 {
398 bare_fn.generic_params
399 } else {
400 &[]
401 };
402 ret.extend(params.iter().filter_map(|p| {
403 let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } =
404 p.kind
405 else {
406 return None;
407 };
408 let hir::ParamName::Plain(name) = p.name else { return None };
409 Some(name.to_string())
410 }));
411
412 if ret.len() >= num_params_to_take {
413 return ret[..num_params_to_take].join(", ");
414 }
415 if let hir::Node::Item(_) = node {
417 break;
418 }
419 }
420
421 self.gen_params
424 .own_params
425 .iter()
426 .skip(self.params_offset + self.num_provided_lifetime_args())
427 .take(num_params_to_take)
428 .map(|param| param.name.to_string())
429 .collect::<Vec<_>>()
430 .join(", ")
431 }
432
433 fn get_type_or_const_args_suggestions_from_param_names(
435 &self,
436 num_params_to_take: usize,
437 ) -> String {
438 let is_in_a_method_call = self
439 .tcx
440 .hir()
441 .parent_iter(self.path_segment.hir_id)
442 .skip(1)
443 .find_map(|(_, node)| match node {
444 hir::Node::Expr(expr) => Some(expr),
445 _ => None,
446 })
447 .is_some_and(|expr| {
448 matches!(
449 expr.kind,
450 hir::ExprKind::MethodCall(hir::PathSegment { args: Some(_), .. }, ..)
451 )
452 });
453
454 let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig);
455 let is_used_in_input = |def_id| {
456 fn_sig.is_some_and(|fn_sig| {
457 fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
458 hir::TyKind::Path(hir::QPath::Resolved(
459 None,
460 hir::Path { res: hir::def::Res::Def(_, id), .. },
461 )) => *id == def_id,
462 _ => false,
463 })
464 })
465 };
466 self.gen_params
467 .own_params
468 .iter()
469 .skip(self.params_offset + self.num_provided_type_or_const_args())
470 .take(num_params_to_take)
471 .map(|param| match param.kind {
472 ty::GenericParamDefKind::Type { .. }
475 if is_in_a_method_call || is_used_in_input(param.def_id) =>
476 {
477 "_"
478 }
479 _ => param.name.as_str(),
480 })
481 .intersperse(", ")
482 .collect()
483 }
484
485 fn get_unbound_associated_types(&self) -> Vec<String> {
486 if self.tcx.is_trait(self.def_id) {
487 let items: &AssocItems = self.tcx.associated_items(self.def_id);
488 items
489 .in_definition_order()
490 .filter(|item| item.kind == AssocKind::Type)
491 .filter(|item| {
492 !self
493 .gen_args
494 .constraints
495 .iter()
496 .any(|constraint| constraint.ident.name == item.name)
497 })
498 .filter(|item| !item.is_impl_trait_in_trait())
499 .map(|item| self.tcx.item_ident(item.def_id).to_string())
500 .collect()
501 } else {
502 Vec::default()
503 }
504 }
505
506 fn create_error_message(&self) -> String {
507 let def_path = self.tcx.def_path_str(self.def_id);
508 let def_kind = self.tcx.def_descr(self.def_id);
509 let (quantifier, bound) = self.get_quantifier_and_bound();
510 let kind = self.kind();
511 let provided_lt_args = self.num_provided_lifetime_args();
512 let provided_type_or_const_args = self.num_provided_type_or_const_args();
513
514 let (provided_args_str, verb) = match self.gen_args_info {
515 MissingLifetimes { .. } | ExcessLifetimes { .. } => (
516 format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)),
517 pluralize!("was", provided_lt_args),
518 ),
519 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => (
520 format!(
521 "{} generic argument{}",
522 provided_type_or_const_args,
523 pluralize!(provided_type_or_const_args)
524 ),
525 pluralize!("was", provided_type_or_const_args),
526 ),
527 };
528
529 if self.gen_args.span_ext().is_some() {
530 format!(
531 "{} takes {}{} {} argument{} but {} {} supplied",
532 def_kind,
533 quantifier,
534 bound,
535 kind,
536 pluralize!(bound),
537 provided_args_str.as_str(),
538 verb
539 )
540 } else {
541 format!("missing generics for {def_kind} `{def_path}`")
542 }
543 }
544
545 fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
547 let (quantifier, bound) = self.get_quantifier_and_bound();
548 let provided_args = self.num_provided_args();
549
550 err.span_label(
551 self.path_segment.ident.span,
552 format!(
553 "expected {}{} {} argument{}",
554 quantifier,
555 bound,
556 self.kind(),
557 pluralize!(bound),
558 ),
559 );
560
561 if self.too_many_args_provided() {
570 return;
571 }
572
573 let args = self
574 .gen_args
575 .args
576 .iter()
577 .skip(self.get_lifetime_args_offset())
578 .take(provided_args)
579 .enumerate();
580
581 for (i, arg) in args {
582 err.span_label(
583 arg.span(),
584 if i + 1 == provided_args {
585 format!(
586 "supplied {} {} argument{}",
587 provided_args,
588 self.kind(),
589 pluralize!(provided_args)
590 )
591 } else {
592 String::new()
593 },
594 );
595 }
596 }
597
598 fn suggest(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
599 debug!(
600 "suggest(self.provided {:?}, self.gen_args.span(): {:?})",
601 self.num_provided_args(),
602 self.gen_args.span(),
603 );
604
605 match self.angle_brackets {
606 AngleBrackets::Missing | AngleBrackets::Implied => self.suggest_adding_args(err),
607 AngleBrackets::Available => {
608 if self.not_enough_args_provided() {
609 self.suggest_adding_args(err);
610 } else if self.too_many_args_provided() {
611 self.suggest_moving_args_from_assoc_fn_to_trait(err);
612 self.suggest_removing_args_or_generics(err);
613 } else {
614 unreachable!();
615 }
616 }
617 }
618 }
619
620 fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
627 if self.gen_args.parenthesized != hir::GenericArgsParentheses::No {
628 return;
629 }
630
631 match self.gen_args_info {
632 MissingLifetimes { .. } => {
633 self.suggest_adding_lifetime_args(err);
634 }
635 MissingTypesOrConsts { .. } => {
636 self.suggest_adding_type_and_const_args(err);
637 }
638 ExcessTypesOrConsts { .. } => {
639 }
641 _ => unreachable!(),
642 }
643 }
644
645 fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
646 debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment);
647 let num_missing_args = self.num_missing_lifetime_args();
648 let num_params_to_take = num_missing_args;
649 let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
650
651 let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
652 self.path_segment.hir_id,
653 num_params_to_take,
654 );
655 debug!("suggested_args: {suggested_args:?}");
656
657 match self.angle_brackets {
658 AngleBrackets::Missing => {
659 let span = self.path_segment.ident.span;
660
661 let sugg = format!("<{suggested_args}>");
663 debug!("sugg: {:?}", sugg);
664
665 err.span_suggestion_verbose(
666 span.shrink_to_hi(),
667 msg,
668 sugg,
669 Applicability::HasPlaceholders,
670 );
671 }
672
673 AngleBrackets::Available => {
674 let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 {
675 (self.gen_args.span().unwrap().shrink_to_lo(), true)
676 } else {
677 let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1];
678 (last_lt.span().shrink_to_hi(), false)
679 };
680 let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
681 let has_constraints = !self.gen_args.constraints.is_empty();
682
683 let sugg_prefix = if is_first { "" } else { ", " };
684 let sugg_suffix =
685 if is_first && (has_non_lt_args || has_constraints) { ", " } else { "" };
686
687 let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}");
688 debug!("sugg: {:?}", sugg);
689
690 err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders);
691 }
692 AngleBrackets::Implied => {
693 unreachable!();
695 }
696 }
697 }
698
699 fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
700 let num_missing_args = self.num_missing_type_or_const_args();
701 let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
702
703 let suggested_args =
704 self.get_type_or_const_args_suggestions_from_param_names(num_missing_args);
705 debug!("suggested_args: {:?}", suggested_args);
706
707 match self.angle_brackets {
708 AngleBrackets::Missing | AngleBrackets::Implied => {
709 let span = self.path_segment.ident.span;
710
711 let sugg = format!("<{suggested_args}>");
713 debug!("sugg: {:?}", sugg);
714
715 err.span_suggestion_verbose(
716 span.shrink_to_hi(),
717 msg,
718 sugg,
719 Applicability::HasPlaceholders,
720 );
721 }
722 AngleBrackets::Available => {
723 let gen_args_span = self.gen_args.span().unwrap();
724 let sugg_offset =
725 self.get_lifetime_args_offset() + self.num_provided_type_or_const_args();
726
727 let (sugg_span, is_first) = if sugg_offset == 0 {
728 (gen_args_span.shrink_to_lo(), true)
729 } else {
730 let arg_span = self.gen_args.args[sugg_offset - 1].span();
731 (arg_span.shrink_to_hi(), arg_span.hi() <= gen_args_span.lo())
739 };
740
741 let sugg_prefix = if is_first { "" } else { ", " };
742 let sugg_suffix =
743 if is_first && !self.gen_args.constraints.is_empty() { ", " } else { "" };
744
745 let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}");
746 debug!("sugg: {:?}", sugg);
747
748 err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders);
749 }
750 }
751 }
752
753 fn suggest_moving_args_from_assoc_fn_to_trait(
760 &self,
761 err: &mut Diag<'_, impl EmissionGuarantee>,
762 ) {
763 let trait_ = match self.tcx.trait_of_item(self.def_id) {
764 Some(def_id) => def_id,
765 None => return,
766 };
767
768 let num_assoc_fn_expected_args =
772 self.num_expected_type_or_const_args() + self.num_expected_lifetime_args();
773 if num_assoc_fn_expected_args > 0 {
774 return;
775 }
776
777 let num_assoc_fn_excess_args =
778 self.num_excess_type_or_const_args() + self.num_excess_lifetime_args();
779
780 let trait_generics = self.tcx.generics_of(trait_);
781 let num_trait_generics_except_self =
782 trait_generics.count() - if trait_generics.has_self { 1 } else { 0 };
783
784 let msg = format!(
785 "consider moving {these} generic argument{s} to the `{name}` trait, which takes up to {num} argument{s}",
786 these = pluralize!("this", num_assoc_fn_excess_args),
787 s = pluralize!(num_assoc_fn_excess_args),
788 name = self.tcx.item_name(trait_),
789 num = num_trait_generics_except_self,
790 );
791
792 if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(self.path_segment.hir_id) {
793 match &expr.kind {
794 hir::ExprKind::Path(qpath) => self
795 .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
796 err,
797 qpath,
798 msg,
799 num_assoc_fn_excess_args,
800 num_trait_generics_except_self,
801 ),
802 hir::ExprKind::MethodCall(..) => self
803 .suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
804 err,
805 trait_,
806 expr,
807 msg,
808 num_assoc_fn_excess_args,
809 num_trait_generics_except_self,
810 ),
811 _ => return,
812 }
813 }
814 }
815
816 fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
817 &self,
818 err: &mut Diag<'_, impl EmissionGuarantee>,
819 qpath: &'tcx hir::QPath<'tcx>,
820 msg: String,
821 num_assoc_fn_excess_args: usize,
822 num_trait_generics_except_self: usize,
823 ) {
824 if let hir::QPath::Resolved(_, path) = qpath
825 && let Some(trait_path_segment) = path.segments.get(0)
826 {
827 let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
828
829 if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args
830 == num_trait_generics_except_self
831 && let Some(span) = self.gen_args.span_ext()
832 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
833 {
834 let sugg = vec![
835 (
836 self.path_segment.ident.span,
837 format!("{}::{}", snippet, self.path_segment.ident),
838 ),
839 (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()),
840 ];
841
842 err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
843 }
844 }
845 }
846
847 fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
848 &self,
849 err: &mut Diag<'_, impl EmissionGuarantee>,
850 trait_def_id: DefId,
851 expr: &'tcx hir::Expr<'tcx>,
852 msg: String,
853 num_assoc_fn_excess_args: usize,
854 num_trait_generics_except_self: usize,
855 ) {
856 let sm = self.tcx.sess.source_map();
857 let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else {
858 return;
859 };
860 if num_assoc_fn_excess_args != num_trait_generics_except_self {
861 return;
862 }
863 let Some(gen_args) = self.gen_args.span_ext() else {
864 return;
865 };
866 let Ok(generics) = sm.span_to_snippet(gen_args) else {
867 return;
868 };
869 let Ok(rcvr) =
870 sm.span_to_snippet(rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span))
871 else {
872 return;
873 };
874 let Ok(rest) = (match args {
875 [] => Ok(String::new()),
876 [arg] => {
877 sm.span_to_snippet(arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span))
878 }
879 [first, .., last] => {
880 let first_span = first.span.find_ancestor_inside(expr.span).unwrap_or(first.span);
881 let last_span = last.span.find_ancestor_inside(expr.span).unwrap_or(last.span);
882 sm.span_to_snippet(first_span.to(last_span))
883 }
884 }) else {
885 return;
886 };
887 let comma = if args.len() > 0 { ", " } else { "" };
888 let trait_path = self.tcx.def_path_str(trait_def_id);
889 let method_name = self.tcx.item_name(self.def_id);
890 err.span_suggestion_verbose(
891 expr.span,
892 msg,
893 format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"),
894 Applicability::MaybeIncorrect,
895 );
896 }
897
898 fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
904 let num_provided_lt_args = self.num_provided_lifetime_args();
905 let num_provided_type_const_args = self.num_provided_type_or_const_args();
906 let unbound_types = self.get_unbound_associated_types();
907 let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
908 assert!(num_provided_args > 0);
909
910 let num_redundant_lt_args = self.num_excess_lifetime_args();
911 let num_redundant_type_or_const_args = self.num_excess_type_or_const_args();
912 let num_redundant_args = num_redundant_lt_args + num_redundant_type_or_const_args;
913
914 let redundant_lifetime_args = num_redundant_lt_args > 0;
915 let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
916
917 let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
918 let provided_args_matches_unbound_traits =
919 unbound_types.len() == num_redundant_type_or_const_args;
920
921 let remove_lifetime_args = |err: &mut Diag<'_, _>| {
922 let mut lt_arg_spans = Vec::new();
923 let mut found_redundant = false;
924 for arg in self.gen_args.args {
925 if let hir::GenericArg::Lifetime(_) = arg {
926 lt_arg_spans.push(arg.span());
927 if lt_arg_spans.len() > self.num_expected_lifetime_args() {
928 found_redundant = true;
929 }
930 } else if found_redundant {
931 break;
938 }
939 }
940
941 let span_lo_redundant_lt_args = if self.num_expected_lifetime_args() == 0 {
942 lt_arg_spans[0]
943 } else {
944 lt_arg_spans[self.num_expected_lifetime_args() - 1]
945 };
946 let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
947
948 let span_redundant_lt_args =
949 span_lo_redundant_lt_args.shrink_to_hi().to(span_hi_redundant_lt_args);
950 debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
951
952 let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
953 let msg_lifetimes =
954 format!("remove the lifetime argument{s}", s = pluralize!(num_redundant_lt_args));
955
956 err.span_suggestion(
957 span_redundant_lt_args,
958 msg_lifetimes,
959 "",
960 Applicability::MaybeIncorrect,
961 );
962 };
963
964 let remove_type_or_const_args = |err: &mut Diag<'_, _>| {
965 let mut gen_arg_spans = Vec::new();
966 let mut found_redundant = false;
967 for arg in self.gen_args.args {
968 match arg {
969 hir::GenericArg::Type(_)
970 | hir::GenericArg::Const(_)
971 | hir::GenericArg::Infer(_) => {
972 gen_arg_spans.push(arg.span());
973 if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
974 found_redundant = true;
975 }
976 }
977 _ if found_redundant => break,
978 _ => {}
979 }
980 }
981
982 let span_lo_redundant_type_or_const_args =
983 if self.num_expected_type_or_const_args() == 0 {
984 gen_arg_spans[0]
985 } else {
986 gen_arg_spans[self.num_expected_type_or_const_args() - 1]
987 };
988 let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
989 let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args
990 .shrink_to_hi()
991 .to(span_hi_redundant_type_or_const_args);
992
993 debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
994
995 let num_redundant_gen_args =
996 gen_arg_spans.len() - self.num_expected_type_or_const_args();
997 let msg_types_or_consts = format!(
998 "remove the unnecessary generic argument{s}",
999 s = pluralize!(num_redundant_gen_args),
1000 );
1001
1002 err.span_suggestion(
1003 span_redundant_type_or_const_args,
1004 msg_types_or_consts,
1005 "",
1006 Applicability::MaybeIncorrect,
1007 );
1008 };
1009
1010 if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
1013 if !self.is_in_trait_impl() {
1016 let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
1017 let suggestions = iter::zip(unused_generics, &unbound_types)
1018 .map(|(potential, name)| {
1019 (potential.span().shrink_to_lo(), format!("{name} = "))
1020 })
1021 .collect::<Vec<_>>();
1022
1023 if !suggestions.is_empty() {
1024 err.multipart_suggestion_verbose(
1025 format!(
1026 "replace the generic bound{s} with the associated type{s}",
1027 s = pluralize!(unbound_types.len())
1028 ),
1029 suggestions,
1030 Applicability::MaybeIncorrect,
1031 );
1032 }
1033 }
1034 } else if remove_entire_generics {
1035 let span = self
1036 .path_segment
1037 .args
1038 .unwrap()
1039 .span_ext()
1040 .unwrap()
1041 .with_lo(self.path_segment.ident.span.hi());
1042
1043 let msg = format!(
1044 "remove the unnecessary {}generics",
1045 if self.gen_args.parenthesized == hir::GenericArgsParentheses::ParenSugar {
1046 "parenthetical "
1047 } else {
1048 ""
1049 },
1050 );
1051
1052 if span.is_empty() {
1053 } else {
1062 err.span_suggestion(span, msg, "", Applicability::MaybeIncorrect);
1063 }
1064 } else if redundant_lifetime_args && redundant_type_or_const_args {
1065 remove_lifetime_args(err);
1066 remove_type_or_const_args(err);
1067 } else if redundant_lifetime_args {
1068 remove_lifetime_args(err);
1069 } else {
1070 assert!(redundant_type_or_const_args);
1071 remove_type_or_const_args(err);
1072 }
1073 }
1074
1075 fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
1077 let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
1078 if self.tcx.sess.source_map().is_span_accessible(def_span) {
1079 def_span.into()
1080 } else {
1081 return;
1082 }
1083 } else {
1084 return;
1085 };
1086
1087 let msg = {
1088 let def_kind = self.tcx.def_descr(self.def_id);
1089 let (quantifier, bound) = self.get_quantifier_and_bound();
1090
1091 let params = if bound == 0 {
1092 String::new()
1093 } else {
1094 let params = self
1095 .gen_params
1096 .own_params
1097 .iter()
1098 .skip(self.params_offset)
1099 .take(bound)
1100 .map(|param| {
1101 let span = self.tcx.def_span(param.def_id);
1102 spans.push_span_label(span, "");
1103 param
1104 })
1105 .map(|param| format!("`{}`", param.name))
1106 .collect::<Vec<_>>()
1107 .join(", ");
1108
1109 format!(": {params}")
1110 };
1111
1112 format!(
1113 "{} defined here, with {}{} {} parameter{}{}",
1114 def_kind,
1115 quantifier,
1116 bound,
1117 self.kind(),
1118 pluralize!(bound),
1119 params,
1120 )
1121 };
1122
1123 err.span_note(spans, msg);
1124 }
1125
1126 fn note_synth_provided(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
1128 if !self.is_synth_provided() {
1129 return;
1130 }
1131
1132 err.note("`impl Trait` cannot be explicitly specified as a generic argument");
1133 }
1134}
1135
1136impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> {
1137 fn into_diag(
1138 self,
1139 dcx: rustc_errors::DiagCtxtHandle<'a>,
1140 level: rustc_errors::Level,
1141 ) -> Diag<'a, G> {
1142 let msg = self.create_error_message();
1143 let mut err = Diag::new(dcx, level, msg);
1144 err.code(E0107);
1145 err.span(self.path_segment.ident.span);
1146
1147 self.notify(&mut err);
1148 self.suggest(&mut err);
1149 self.show_definition(&mut err);
1150 self.note_synth_provided(&mut err);
1151
1152 err
1153 }
1154}