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