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