]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
Rollup merge of #97301 - semicoleon:unstable-reexport, r=petrochenkov
[rust.git] / compiler / rustc_typeck / src / structured_errors / wrong_number_of_generic_args.rs
1 use crate::structured_errors::StructuredDiagnostic;
2 use rustc_errors::{
3     pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed,
4     MultiSpan,
5 };
6 use rustc_hir as hir;
7 use rustc_middle::hir::map::fn_sig;
8 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
9 use rustc_session::Session;
10 use rustc_span::def_id::DefId;
11 use std::iter;
12
13 use GenericArgsInfo::*;
14
15 /// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
16 pub struct WrongNumberOfGenericArgs<'a, 'tcx> {
17     pub(crate) tcx: TyCtxt<'tcx>,
18
19     pub(crate) angle_brackets: AngleBrackets,
20
21     pub(crate) gen_args_info: GenericArgsInfo,
22
23     /// Offending path segment
24     pub(crate) path_segment: &'a hir::PathSegment<'a>,
25
26     /// Generic parameters as expected by type or trait
27     pub(crate) gen_params: &'a ty::Generics,
28
29     /// Index offset into parameters. Depends on whether `Self` is included and on
30     /// number of lifetime parameters in case we're processing missing or redundant
31     /// type or constant arguments.
32     pub(crate) params_offset: usize,
33
34     /// Generic arguments as provided by user
35     pub(crate) gen_args: &'a hir::GenericArgs<'a>,
36
37     /// DefId of the generic type
38     pub(crate) def_id: DefId,
39 }
40
41 // Provides information about the kind of arguments that were provided for
42 // the PathSegment, for which missing generic arguments were detected
43 #[derive(Debug)]
44 pub(crate) enum AngleBrackets {
45     // No angle brackets were provided, but generic arguments exist in elided form
46     Implied,
47
48     // No angle brackets were provided
49     Missing,
50
51     // Angle brackets are available, but missing some generic arguments
52     Available,
53 }
54
55 // Information about the kind of arguments that are either missing or are unexpected
56 #[derive(Debug)]
57 pub enum GenericArgsInfo {
58     MissingLifetimes {
59         num_missing_args: usize,
60     },
61     ExcessLifetimes {
62         num_redundant_args: usize,
63     },
64     MissingTypesOrConsts {
65         num_missing_args: usize,
66
67         // type or const generic arguments can have default values
68         num_default_params: usize,
69
70         // lifetime arguments precede type and const parameters, this
71         // field gives the number of generic lifetime arguments to let
72         // us infer the position of type and const generic arguments
73         // in the angle brackets
74         args_offset: usize,
75     },
76
77     ExcessTypesOrConsts {
78         num_redundant_args: usize,
79
80         // type or const generic arguments can have default values
81         num_default_params: usize,
82
83         // lifetime arguments precede type and const parameters, this
84         // field gives the number of generic lifetime arguments to let
85         // us infer the position of type and const generic arguments
86         // in the angle brackets
87         args_offset: usize,
88
89         // if synthetic type arguments (e.g. `impl Trait`) are specified
90         synth_provided: bool,
91     },
92 }
93
94 impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
95     pub fn new(
96         tcx: TyCtxt<'tcx>,
97         gen_args_info: GenericArgsInfo,
98         path_segment: &'a hir::PathSegment<'_>,
99         gen_params: &'a ty::Generics,
100         params_offset: usize,
101         gen_args: &'a hir::GenericArgs<'a>,
102         def_id: DefId,
103     ) -> Self {
104         let angle_brackets = if gen_args.span_ext().is_none() {
105             if gen_args.is_empty() { AngleBrackets::Missing } else { AngleBrackets::Implied }
106         } else {
107             AngleBrackets::Available
108         };
109
110         Self {
111             tcx,
112             angle_brackets,
113             gen_args_info,
114             path_segment,
115             gen_params,
116             params_offset,
117             gen_args,
118             def_id,
119         }
120     }
121
122     fn missing_lifetimes(&self) -> bool {
123         match self.gen_args_info {
124             MissingLifetimes { .. } | ExcessLifetimes { .. } => true,
125             MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => false,
126         }
127     }
128
129     fn kind(&self) -> String {
130         if self.missing_lifetimes() { "lifetime".to_string() } else { "generic".to_string() }
131     }
132
133     fn num_provided_args(&self) -> usize {
134         if self.missing_lifetimes() {
135             self.num_provided_lifetime_args()
136         } else {
137             self.num_provided_type_or_const_args()
138         }
139     }
140
141     fn num_provided_lifetime_args(&self) -> usize {
142         match self.angle_brackets {
143             AngleBrackets::Missing => 0,
144             // Only lifetime arguments can be implied
145             AngleBrackets::Implied => self.gen_args.args.len(),
146             AngleBrackets::Available => self.gen_args.num_lifetime_params(),
147         }
148     }
149
150     fn num_provided_type_or_const_args(&self) -> usize {
151         match self.angle_brackets {
152             AngleBrackets::Missing => 0,
153             // Only lifetime arguments can be implied
154             AngleBrackets::Implied => 0,
155             AngleBrackets::Available => self.gen_args.num_generic_params(),
156         }
157     }
158
159     fn num_expected_lifetime_args(&self) -> usize {
160         let num_provided_args = self.num_provided_lifetime_args();
161         match self.gen_args_info {
162             MissingLifetimes { num_missing_args } => num_provided_args + num_missing_args,
163             ExcessLifetimes { num_redundant_args } => num_provided_args - num_redundant_args,
164             _ => 0,
165         }
166     }
167
168     fn num_expected_type_or_const_args(&self) -> usize {
169         let num_provided_args = self.num_provided_type_or_const_args();
170         match self.gen_args_info {
171             MissingTypesOrConsts { num_missing_args, .. } => num_provided_args + num_missing_args,
172             ExcessTypesOrConsts { num_redundant_args, .. } => {
173                 num_provided_args - num_redundant_args
174             }
175             _ => 0,
176         }
177     }
178
179     // Gives the number of expected arguments taking into account default arguments
180     fn num_expected_type_or_const_args_including_defaults(&self) -> usize {
181         let provided_args = self.num_provided_type_or_const_args();
182         match self.gen_args_info {
183             MissingTypesOrConsts { num_missing_args, num_default_params, .. } => {
184                 provided_args + num_missing_args - num_default_params
185             }
186             ExcessTypesOrConsts { num_redundant_args, num_default_params, .. } => {
187                 provided_args - num_redundant_args - num_default_params
188             }
189             _ => 0,
190         }
191     }
192
193     fn num_missing_lifetime_args(&self) -> usize {
194         let missing_args = self.num_expected_lifetime_args() - self.num_provided_lifetime_args();
195         assert!(missing_args > 0);
196         missing_args
197     }
198
199     fn num_missing_type_or_const_args(&self) -> usize {
200         let missing_args = self.num_expected_type_or_const_args_including_defaults()
201             - self.num_provided_type_or_const_args();
202         assert!(missing_args > 0);
203         missing_args
204     }
205
206     fn num_excess_lifetime_args(&self) -> usize {
207         match self.gen_args_info {
208             ExcessLifetimes { num_redundant_args } => num_redundant_args,
209             _ => 0,
210         }
211     }
212
213     fn num_excess_type_or_const_args(&self) -> usize {
214         match self.gen_args_info {
215             ExcessTypesOrConsts { num_redundant_args, .. } => num_redundant_args,
216             _ => 0,
217         }
218     }
219
220     fn too_many_args_provided(&self) -> bool {
221         match self.gen_args_info {
222             MissingLifetimes { .. } | MissingTypesOrConsts { .. } => false,
223             ExcessLifetimes { num_redundant_args }
224             | ExcessTypesOrConsts { num_redundant_args, .. } => {
225                 assert!(num_redundant_args > 0);
226                 true
227             }
228         }
229     }
230
231     fn not_enough_args_provided(&self) -> bool {
232         match self.gen_args_info {
233             MissingLifetimes { num_missing_args }
234             | MissingTypesOrConsts { num_missing_args, .. } => {
235                 assert!(num_missing_args > 0);
236                 true
237             }
238             ExcessLifetimes { .. } | ExcessTypesOrConsts { .. } => false,
239         }
240     }
241
242     // Helper method to get the index offset in angle brackets, at which type or const arguments
243     // start appearing
244     fn get_lifetime_args_offset(&self) -> usize {
245         match self.gen_args_info {
246             MissingLifetimes { .. } | ExcessLifetimes { .. } => 0,
247             MissingTypesOrConsts { args_offset, .. } | ExcessTypesOrConsts { args_offset, .. } => {
248                 args_offset
249             }
250         }
251     }
252
253     fn get_num_default_params(&self) -> usize {
254         match self.gen_args_info {
255             MissingTypesOrConsts { num_default_params, .. }
256             | ExcessTypesOrConsts { num_default_params, .. } => num_default_params,
257             _ => 0,
258         }
259     }
260
261     fn is_synth_provided(&self) -> bool {
262         match self.gen_args_info {
263             ExcessTypesOrConsts { synth_provided, .. } => synth_provided,
264             _ => false,
265         }
266     }
267
268     // Helper function to choose a quantifier word for the number of expected arguments
269     // and to give a bound for the number of expected arguments
270     fn get_quantifier_and_bound(&self) -> (&'static str, usize) {
271         if self.get_num_default_params() == 0 {
272             match self.gen_args_info {
273                 MissingLifetimes { .. } | ExcessLifetimes { .. } => {
274                     ("", self.num_expected_lifetime_args())
275                 }
276                 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => {
277                     ("", self.num_expected_type_or_const_args())
278                 }
279             }
280         } else {
281             match self.gen_args_info {
282                 MissingLifetimes { .. } => ("at least ", self.num_expected_lifetime_args()),
283                 MissingTypesOrConsts { .. } => {
284                     ("at least ", self.num_expected_type_or_const_args_including_defaults())
285                 }
286                 ExcessLifetimes { .. } => ("at most ", self.num_expected_lifetime_args()),
287                 ExcessTypesOrConsts { .. } => ("at most ", self.num_expected_type_or_const_args()),
288             }
289         }
290     }
291
292     // Creates lifetime name suggestions from the lifetime parameter names
293     fn get_lifetime_args_suggestions_from_param_names(
294         &self,
295         path_hir_id: Option<hir::HirId>,
296         num_params_to_take: usize,
297     ) -> String {
298         debug!(?path_hir_id);
299
300         if let Some(path_hir_id) = path_hir_id {
301             let mut ret = Vec::new();
302             for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
303                 debug!(?id);
304                 let params = if let Some(generics) = node.generics() {
305                     generics.params
306                 } else if let hir::Node::Ty(ty) = node
307                     && let hir::TyKind::BareFn(bare_fn) = ty.kind
308                 {
309                     bare_fn.generic_params
310                 } else {
311                     &[]
312                 };
313                 ret.extend(params.iter().filter_map(|p| {
314                     let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
315                         = p.kind
316                     else { return None };
317                     let hir::ParamName::Plain(name) = p.name else { return None };
318                     Some(name.to_string())
319                 }));
320                 // Suggest `'static` when in const/static item-like.
321                 if let hir::Node::Item(hir::Item {
322                     kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
323                     ..
324                 })
325                 | hir::Node::TraitItem(hir::TraitItem {
326                     kind: hir::TraitItemKind::Const { .. },
327                     ..
328                 })
329                 | hir::Node::ImplItem(hir::ImplItem {
330                     kind: hir::ImplItemKind::Const { .. },
331                     ..
332                 })
333                 | hir::Node::ForeignItem(hir::ForeignItem {
334                     kind: hir::ForeignItemKind::Static { .. },
335                     ..
336                 })
337                 | hir::Node::AnonConst(..) = node
338                 {
339                     ret.extend(
340                         std::iter::repeat("'static".to_owned())
341                             .take(num_params_to_take.saturating_sub(ret.len())),
342                     );
343                 }
344                 if ret.len() >= num_params_to_take {
345                     return ret[..num_params_to_take].join(", ");
346                 }
347                 // We cannot refer to lifetimes defined in an outer function.
348                 if let hir::Node::Item(_) = node {
349                     break;
350                 }
351             }
352         }
353
354         // We could not gather enough lifetime parameters in the scope.
355         // We use the parameter names from the target type's definition instead.
356         self.gen_params
357             .params
358             .iter()
359             .skip(self.params_offset + self.num_provided_lifetime_args())
360             .take(num_params_to_take)
361             .map(|param| param.name.to_string())
362             .collect::<Vec<_>>()
363             .join(", ")
364     }
365
366     // Creates type or constant name suggestions from the provided parameter names
367     fn get_type_or_const_args_suggestions_from_param_names(
368         &self,
369         num_params_to_take: usize,
370     ) -> String {
371         let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(fn_sig);
372         let is_used_in_input = |def_id| {
373             fn_sig.map_or(false, |fn_sig| {
374                 fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
375                     hir::TyKind::Path(hir::QPath::Resolved(
376                         None,
377                         hir::Path { res: hir::def::Res::Def(_, id), .. },
378                     )) => *id == def_id,
379                     _ => false,
380                 })
381             })
382         };
383         self.gen_params
384             .params
385             .iter()
386             .skip(self.params_offset + self.num_provided_type_or_const_args())
387             .take(num_params_to_take)
388             .map(|param| match param.kind {
389                 // This is being inferred from the item's inputs, no need to set it.
390                 ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
391                     "_".to_string()
392                 }
393                 _ => param.name.to_string(),
394             })
395             .collect::<Vec<_>>()
396             .join(", ")
397     }
398
399     fn get_unbound_associated_types(&self) -> Vec<String> {
400         if self.tcx.is_trait(self.def_id) {
401             let items: &AssocItems<'_> = self.tcx.associated_items(self.def_id);
402             items
403                 .in_definition_order()
404                 .filter(|item| item.kind == AssocKind::Type)
405                 .filter(|item| {
406                     !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
407                 })
408                 .map(|item| item.name.to_ident_string())
409                 .collect()
410         } else {
411             Vec::default()
412         }
413     }
414
415     fn create_error_message(&self) -> String {
416         let def_path = self.tcx.def_path_str(self.def_id);
417         let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
418         let (quantifier, bound) = self.get_quantifier_and_bound();
419         let kind = self.kind();
420         let provided_lt_args = self.num_provided_lifetime_args();
421         let provided_type_or_const_args = self.num_provided_type_or_const_args();
422
423         let get_verb = |num_args| if num_args == 1 { "was" } else { "were" };
424
425         let (provided_args_str, verb) = match self.gen_args_info {
426             MissingLifetimes { .. } | ExcessLifetimes { .. } => (
427                 format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)),
428                 get_verb(provided_lt_args),
429             ),
430             MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => (
431                 format!(
432                     "{} generic argument{}",
433                     provided_type_or_const_args,
434                     pluralize!(provided_type_or_const_args)
435                 ),
436                 get_verb(provided_type_or_const_args),
437             ),
438         };
439
440         if self.gen_args.span_ext().is_some() {
441             format!(
442                 "this {} takes {}{} {} argument{} but {} {} supplied",
443                 def_kind,
444                 quantifier,
445                 bound,
446                 kind,
447                 pluralize!(bound),
448                 provided_args_str.as_str(),
449                 verb
450             )
451         } else {
452             format!("missing generics for {} `{}`", def_kind, def_path)
453         }
454     }
455
456     fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
457         let span = self.path_segment.ident.span;
458         let msg = self.create_error_message();
459
460         self.tcx.sess.struct_span_err_with_code(span, &msg, self.code())
461     }
462
463     /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
464     fn notify(&self, err: &mut Diagnostic) {
465         let (quantifier, bound) = self.get_quantifier_and_bound();
466         let provided_args = self.num_provided_args();
467
468         err.span_label(
469             self.path_segment.ident.span,
470             format!(
471                 "expected {}{} {} argument{}",
472                 quantifier,
473                 bound,
474                 self.kind(),
475                 pluralize!(bound),
476             ),
477         );
478
479         // When too many arguments were provided, we don't highlight each of them, because it
480         // would overlap with the suggestion to remove them:
481         //
482         // ```
483         // type Foo = Bar<usize, usize>;
484         //                -----  ----- supplied 2 type arguments
485         //                     ^^^^^^^ remove this type argument
486         // ```
487         if self.too_many_args_provided() {
488             return;
489         }
490
491         let args = self
492             .gen_args
493             .args
494             .iter()
495             .skip(self.get_lifetime_args_offset())
496             .take(provided_args)
497             .enumerate();
498
499         for (i, arg) in args {
500             err.span_label(
501                 arg.span(),
502                 if i + 1 == provided_args {
503                     format!(
504                         "supplied {} {} argument{}",
505                         provided_args,
506                         self.kind(),
507                         pluralize!(provided_args)
508                     )
509                 } else {
510                     String::new()
511                 },
512             );
513         }
514     }
515
516     fn suggest(&self, err: &mut Diagnostic) {
517         debug!(
518             "suggest(self.provided {:?}, self.gen_args.span(): {:?})",
519             self.num_provided_args(),
520             self.gen_args.span(),
521         );
522
523         match self.angle_brackets {
524             AngleBrackets::Missing | AngleBrackets::Implied => self.suggest_adding_args(err),
525             AngleBrackets::Available => {
526                 if self.not_enough_args_provided() {
527                     self.suggest_adding_args(err);
528                 } else if self.too_many_args_provided() {
529                     self.suggest_removing_args_or_generics(err);
530                 } else {
531                     unreachable!();
532                 }
533             }
534         }
535     }
536
537     /// Suggests to add missing argument(s) when current invocation site already contains some
538     /// generics:
539     ///
540     /// ```text
541     /// type Map = HashMap<String>;
542     /// ```
543     fn suggest_adding_args(&self, err: &mut Diagnostic) {
544         if self.gen_args.parenthesized {
545             return;
546         }
547
548         match self.gen_args_info {
549             MissingLifetimes { .. } => {
550                 self.suggest_adding_lifetime_args(err);
551             }
552             MissingTypesOrConsts { .. } => {
553                 self.suggest_adding_type_and_const_args(err);
554             }
555             _ => unreachable!(),
556         }
557     }
558
559     fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) {
560         debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment);
561         let num_missing_args = self.num_missing_lifetime_args();
562         let num_params_to_take = num_missing_args;
563         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
564
565         let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
566             self.path_segment.hir_id,
567             num_params_to_take,
568         );
569         debug!("suggested_args: {:?}", &suggested_args);
570
571         match self.angle_brackets {
572             AngleBrackets::Missing => {
573                 let span = self.path_segment.ident.span;
574
575                 // insert a suggestion of the form "Y<'a, 'b>"
576                 let ident = self.path_segment.ident.name.to_ident_string();
577                 let sugg = format!("{}<{}>", ident, suggested_args);
578                 debug!("sugg: {:?}", sugg);
579
580                 err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
581             }
582
583             AngleBrackets::Available => {
584                 let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 {
585                     (self.gen_args.span().unwrap().shrink_to_lo(), true)
586                 } else {
587                     let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1];
588                     (last_lt.span().shrink_to_hi(), false)
589                 };
590                 let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
591                 let has_bindings = !self.gen_args.bindings.is_empty();
592
593                 let sugg_prefix = if is_first { "" } else { ", " };
594                 let sugg_suffix =
595                     if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" };
596
597                 let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
598                 debug!("sugg: {:?}", sugg);
599
600                 err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
601             }
602             AngleBrackets::Implied => {
603                 // We never encounter missing lifetimes in situations in which lifetimes are elided
604                 unreachable!();
605             }
606         }
607     }
608
609     fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
610         let num_missing_args = self.num_missing_type_or_const_args();
611         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
612
613         let suggested_args =
614             self.get_type_or_const_args_suggestions_from_param_names(num_missing_args);
615         debug!("suggested_args: {:?}", suggested_args);
616
617         match self.angle_brackets {
618             AngleBrackets::Missing | AngleBrackets::Implied => {
619                 let span = self.path_segment.ident.span;
620
621                 // insert a suggestion of the form "Y<T, U>"
622                 let ident = self.path_segment.ident.name.to_ident_string();
623                 let sugg = format!("{}<{}>", ident, suggested_args);
624                 debug!("sugg: {:?}", sugg);
625
626                 err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
627             }
628             AngleBrackets::Available => {
629                 let gen_args_span = self.gen_args.span().unwrap();
630                 let sugg_offset =
631                     self.get_lifetime_args_offset() + self.num_provided_type_or_const_args();
632
633                 let (sugg_span, is_first) = if sugg_offset == 0 {
634                     (gen_args_span.shrink_to_lo(), true)
635                 } else {
636                     let arg_span = self.gen_args.args[sugg_offset - 1].span();
637                     // If we came here then inferred lifetime's spans can only point
638                     // to either the opening bracket or to the space right after.
639                     // Both of these spans have an `hi` lower than or equal to the span
640                     // of the generics excluding the brackets.
641                     // This allows us to check if `arg_span` is the artificial span of
642                     // an inferred lifetime, in which case the generic we're suggesting to
643                     // add will be the first visible, even if it isn't the actual first generic.
644                     (arg_span.shrink_to_hi(), arg_span.hi() <= gen_args_span.lo())
645                 };
646
647                 let sugg_prefix = if is_first { "" } else { ", " };
648                 let sugg_suffix =
649                     if is_first && !self.gen_args.bindings.is_empty() { ", " } else { "" };
650
651                 let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
652                 debug!("sugg: {:?}", sugg);
653
654                 err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
655             }
656         }
657     }
658
659     /// Suggests to remove redundant argument(s):
660     ///
661     /// ```text
662     /// type Map = HashMap<String, String, String, String>;
663     /// ```
664     fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
665         let num_provided_lt_args = self.num_provided_lifetime_args();
666         let num_provided_type_const_args = self.num_provided_type_or_const_args();
667         let unbound_types = self.get_unbound_associated_types();
668         let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
669         assert!(num_provided_args > 0);
670
671         let num_redundant_lt_args = self.num_excess_lifetime_args();
672         let num_redundant_type_or_const_args = self.num_excess_type_or_const_args();
673         let num_redundant_args = num_redundant_lt_args + num_redundant_type_or_const_args;
674
675         let redundant_lifetime_args = num_redundant_lt_args > 0;
676         let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
677
678         let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
679         let provided_args_matches_unbound_traits =
680             unbound_types.len() == num_redundant_type_or_const_args;
681
682         let remove_lifetime_args = |err: &mut Diagnostic| {
683             let mut lt_arg_spans = Vec::new();
684             let mut found_redundant = false;
685             for arg in self.gen_args.args {
686                 if let hir::GenericArg::Lifetime(_) = arg {
687                     lt_arg_spans.push(arg.span());
688                     if lt_arg_spans.len() > self.num_expected_lifetime_args() {
689                         found_redundant = true;
690                     }
691                 } else if found_redundant {
692                     // Argument which is redundant and separated like this `'c`
693                     // is not included to avoid including `Bar` in span.
694                     // ```
695                     // type Foo<'a, T> = &'a T;
696                     // let _: Foo<'a, 'b, Bar, 'c>;
697                     // ```
698                     break;
699                 }
700             }
701
702             let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
703             let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
704
705             let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
706             debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
707
708             let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
709             let msg_lifetimes = format!(
710                 "remove {these} lifetime argument{s}",
711                 these = pluralize!("this", num_redundant_lt_args),
712                 s = pluralize!(num_redundant_lt_args),
713             );
714
715             err.span_suggestion(
716                 span_redundant_lt_args,
717                 &msg_lifetimes,
718                 String::new(),
719                 Applicability::MaybeIncorrect,
720             );
721         };
722
723         let remove_type_or_const_args = |err: &mut Diagnostic| {
724             let mut gen_arg_spans = Vec::new();
725             let mut found_redundant = false;
726             for arg in self.gen_args.args {
727                 match arg {
728                     hir::GenericArg::Type(_)
729                     | hir::GenericArg::Const(_)
730                     | hir::GenericArg::Infer(_) => {
731                         gen_arg_spans.push(arg.span());
732                         if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
733                             found_redundant = true;
734                         }
735                     }
736                     _ if found_redundant => break,
737                     _ => {}
738                 }
739             }
740
741             let span_lo_redundant_type_or_const_args =
742                 gen_arg_spans[self.num_expected_type_or_const_args()];
743             let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
744
745             let span_redundant_type_or_const_args =
746                 span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
747             debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
748
749             let num_redundant_gen_args =
750                 gen_arg_spans.len() - self.num_expected_type_or_const_args();
751             let msg_types_or_consts = format!(
752                 "remove {these} generic argument{s}",
753                 these = pluralize!("this", num_redundant_gen_args),
754                 s = pluralize!(num_redundant_gen_args),
755             );
756
757             err.span_suggestion(
758                 span_redundant_type_or_const_args,
759                 &msg_types_or_consts,
760                 String::new(),
761                 Applicability::MaybeIncorrect,
762             );
763         };
764
765         // If there is a single unbound associated type and a single excess generic param
766         // suggest replacing the generic param with the associated type bound
767         if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
768             let mut suggestions = vec![];
769             let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
770             for (potential, name) in iter::zip(unused_generics, &unbound_types) {
771                 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) {
772                     suggestions.push((potential.span(), format!("{} = {}", name, snippet)));
773                 }
774             }
775
776             if !suggestions.is_empty() {
777                 err.multipart_suggestion(
778                     &format!(
779                         "replace the generic bound{s} with the associated type{s}",
780                         s = pluralize!(unbound_types.len())
781                     ),
782                     suggestions,
783                     Applicability::MaybeIncorrect,
784                 );
785             }
786         } else if remove_entire_generics {
787             let span = self
788                 .path_segment
789                 .args
790                 .unwrap()
791                 .span_ext()
792                 .unwrap()
793                 .with_lo(self.path_segment.ident.span.hi());
794
795             let msg = format!(
796                 "remove these {}generics",
797                 if self.gen_args.parenthesized { "parenthetical " } else { "" },
798             );
799
800             err.span_suggestion(span, &msg, String::new(), Applicability::MaybeIncorrect);
801         } else if redundant_lifetime_args && redundant_type_or_const_args {
802             remove_lifetime_args(err);
803             remove_type_or_const_args(err);
804         } else if redundant_lifetime_args {
805             remove_lifetime_args(err);
806         } else {
807             assert!(redundant_type_or_const_args);
808             remove_type_or_const_args(err);
809         }
810     }
811
812     /// Builds the `type defined here` message.
813     fn show_definition(&self, err: &mut Diagnostic) {
814         let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
815             if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
816                 def_span.into()
817             } else {
818                 return;
819             }
820         } else {
821             return;
822         };
823
824         let msg = {
825             let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
826             let (quantifier, bound) = self.get_quantifier_and_bound();
827
828             let params = if bound == 0 {
829                 String::new()
830             } else {
831                 let params = self
832                     .gen_params
833                     .params
834                     .iter()
835                     .skip(self.params_offset)
836                     .take(bound)
837                     .map(|param| {
838                         let span = self.tcx.def_span(param.def_id);
839                         spans.push_span_label(span, String::new());
840                         param
841                     })
842                     .map(|param| format!("`{}`", param.name))
843                     .collect::<Vec<_>>()
844                     .join(", ");
845
846                 format!(": {}", params)
847             };
848
849             format!(
850                 "{} defined here, with {}{} {} parameter{}{}",
851                 def_kind,
852                 quantifier,
853                 bound,
854                 self.kind(),
855                 pluralize!(bound),
856                 params,
857             )
858         };
859
860         err.span_note(spans, &msg);
861     }
862
863     /// Add note if `impl Trait` is explicitly specified.
864     fn note_synth_provided(&self, err: &mut Diagnostic) {
865         if !self.is_synth_provided() {
866             return;
867         }
868
869         err.note("`impl Trait` cannot be explicitly specified as a generic argument");
870     }
871 }
872
873 impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
874     fn session(&self) -> &Session {
875         self.tcx.sess
876     }
877
878     fn code(&self) -> DiagnosticId {
879         rustc_errors::error_code!(E0107)
880     }
881
882     fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
883         let mut err = self.start_diagnostics();
884
885         self.notify(&mut err);
886         self.suggest(&mut err);
887         self.show_definition(&mut err);
888         self.note_synth_provided(&mut err);
889
890         err
891     }
892 }