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