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