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