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