]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / structured_errors / wrong_number_of_generic_args.rs
CommitLineData
5869c6ff 1use crate::structured_errors::StructuredDiagnostic;
5e7ed085
FG
2use rustc_errors::{
3 pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed,
4};
5869c6ff 5use rustc_hir as hir;
c295e0f8 6use rustc_middle::hir::map::fn_sig;
17df50a5 7use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
5869c6ff
XL
8use rustc_middle::ty::{self as ty, TyCtxt};
9use rustc_session::Session;
5869c6ff
XL
10use rustc_span::{def_id::DefId, MultiSpan};
11
17df50a5
XL
12use GenericArgsInfo::*;
13
5869c6ff
XL
14/// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
15pub struct WrongNumberOfGenericArgs<'a, 'tcx> {
16 crate tcx: TyCtxt<'tcx>,
17
17df50a5 18 crate angle_brackets: AngleBrackets,
5869c6ff 19
17df50a5 20 crate gen_args_info: GenericArgsInfo,
5869c6ff
XL
21
22 /// Offending path segment
23 crate path_segment: &'a hir::PathSegment<'a>,
24
25 /// Generic parameters as expected by type or trait
26 crate gen_params: &'a ty::Generics,
27
17df50a5
XL
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 crate params_offset: usize,
32
5869c6ff
XL
33 /// Generic arguments as provided by user
34 crate gen_args: &'a hir::GenericArgs<'a>,
35
36 /// DefId of the generic type
37 crate def_id: DefId,
17df50a5
XL
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)]
43pub(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}
5869c6ff 53
17df50a5
XL
54// Information about the kind of arguments that are either missing or are unexpected
55#[derive(Debug)]
56pub 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,
5e7ed085
FG
87
88 // if synthetic type arguments (e.g. `impl Trait`) are specified
89 synth_provided: bool,
17df50a5 90 },
5869c6ff
XL
91}
92
17df50a5
XL
93impl<'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 }
5869c6ff 105 } else {
17df50a5
XL
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,
5869c6ff
XL
118 }
119 }
120
17df50a5
XL
121 fn missing_lifetimes(&self) -> bool {
122 match self.gen_args_info {
123 MissingLifetimes { .. } | ExcessLifetimes { .. } => true,
124 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => false,
125 }
126 }
5869c6ff 127
17df50a5
XL
128 fn kind(&self) -> String {
129 if self.missing_lifetimes() { "lifetime".to_string() } else { "generic".to_string() }
130 }
5869c6ff 131
17df50a5
XL
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(),
c295e0f8 145 AngleBrackets::Available => self.gen_args.num_lifetime_params(),
17df50a5
XL
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,
c295e0f8 154 AngleBrackets::Available => self.gen_args.num_generic_params(),
17df50a5
XL
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
5869c6ff 173 }
17df50a5
XL
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
5e7ed085
FG
260 fn is_synth_provided(&self) -> bool {
261 match self.gen_args_info {
262 ExcessTypesOrConsts { synth_provided, .. } => synth_provided,
263 _ => false,
264 }
265 }
266
17df50a5
XL
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(&self, num_params_to_take: usize) -> String {
293 self.gen_params
294 .params
295 .iter()
296 .skip(self.params_offset + self.num_provided_lifetime_args())
297 .take(num_params_to_take)
298 .map(|param| param.name.to_string())
299 .collect::<Vec<_>>()
300 .join(", ")
301 }
302
303 // Creates type or constant name suggestions from the provided parameter names
304 fn get_type_or_const_args_suggestions_from_param_names(
305 &self,
306 num_params_to_take: usize,
307 ) -> String {
c295e0f8
XL
308 let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(fn_sig);
309 let is_used_in_input = |def_id| {
310 fn_sig.map_or(false, |fn_sig| {
311 fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
312 hir::TyKind::Path(hir::QPath::Resolved(
313 None,
314 hir::Path { res: hir::def::Res::Def(_, id), .. },
3c0e092e 315 )) => *id == def_id,
c295e0f8
XL
316 _ => false,
317 })
318 })
319 };
17df50a5
XL
320 self.gen_params
321 .params
322 .iter()
323 .skip(self.params_offset + self.num_provided_type_or_const_args())
324 .take(num_params_to_take)
c295e0f8 325 .map(|param| match param.kind {
5e7ed085 326 // This is being inferred from the item's inputs, no need to set it.
c295e0f8
XL
327 ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
328 "_".to_string()
329 }
330 _ => param.name.to_string(),
331 })
17df50a5
XL
332 .collect::<Vec<_>>()
333 .join(", ")
334 }
335
336 fn create_error_message(&self) -> String {
337 let def_path = self.tcx.def_path_str(self.def_id);
338 let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
339 let (quantifier, bound) = self.get_quantifier_and_bound();
340 let kind = self.kind();
341 let provided_lt_args = self.num_provided_lifetime_args();
342 let provided_type_or_const_args = self.num_provided_type_or_const_args();
343
344 let get_verb = |num_args| if num_args == 1 { "was" } else { "were" };
345
346 let (provided_args_str, verb) = match self.gen_args_info {
347 MissingLifetimes { .. } | ExcessLifetimes { .. } => (
348 format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)),
349 get_verb(provided_lt_args),
350 ),
351 MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => (
352 format!(
353 "{} generic argument{}",
354 provided_type_or_const_args,
355 pluralize!(provided_type_or_const_args)
356 ),
357 get_verb(provided_type_or_const_args),
358 ),
5869c6ff
XL
359 };
360
17df50a5
XL
361 if self.gen_args.span_ext().is_some() {
362 format!(
363 "this {} takes {}{} {} argument{} but {} {} supplied",
364 def_kind,
365 quantifier,
366 bound,
367 kind,
368 pluralize!(bound),
369 provided_args_str.as_str(),
370 verb
371 )
372 } else {
373 format!("missing generics for {} `{}`", def_kind, def_path)
374 }
375 }
376
5e7ed085 377 fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
17df50a5
XL
378 let span = self.path_segment.ident.span;
379 let msg = self.create_error_message();
380
5869c6ff
XL
381 self.tcx.sess.struct_span_err_with_code(span, &msg, self.code())
382 }
383
384 /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
5e7ed085 385 fn notify(&self, err: &mut Diagnostic) {
17df50a5
XL
386 let (quantifier, bound) = self.get_quantifier_and_bound();
387 let provided_args = self.num_provided_args();
5869c6ff
XL
388
389 err.span_label(
390 self.path_segment.ident.span,
391 format!(
392 "expected {}{} {} argument{}",
393 quantifier,
394 bound,
17df50a5 395 self.kind(),
5869c6ff
XL
396 pluralize!(bound),
397 ),
398 );
399
17df50a5 400 // When too many arguments were provided, we don't highlight each of them, because it
5869c6ff
XL
401 // would overlap with the suggestion to remove them:
402 //
403 // ```
404 // type Foo = Bar<usize, usize>;
405 // ----- ----- supplied 2 type arguments
406 // ^^^^^^^ remove this type argument
407 // ```
17df50a5 408 if self.too_many_args_provided() {
5869c6ff
XL
409 return;
410 }
411
17df50a5
XL
412 let args = self
413 .gen_args
414 .args
415 .iter()
416 .skip(self.get_lifetime_args_offset())
417 .take(provided_args)
418 .enumerate();
5869c6ff
XL
419
420 for (i, arg) in args {
421 err.span_label(
422 arg.span(),
17df50a5 423 if i + 1 == provided_args {
5869c6ff
XL
424 format!(
425 "supplied {} {} argument{}",
17df50a5
XL
426 provided_args,
427 self.kind(),
428 pluralize!(provided_args)
5869c6ff
XL
429 )
430 } else {
431 String::new()
432 },
433 );
434 }
435 }
436
5e7ed085 437 fn suggest(&self, err: &mut Diagnostic) {
17df50a5
XL
438 debug!(
439 "suggest(self.provided {:?}, self.gen_args.span(): {:?})",
440 self.num_provided_args(),
441 self.gen_args.span(),
5869c6ff
XL
442 );
443
17df50a5
XL
444 match self.angle_brackets {
445 AngleBrackets::Missing | AngleBrackets::Implied => self.suggest_adding_args(err),
446 AngleBrackets::Available => {
447 if self.not_enough_args_provided() {
448 self.suggest_adding_args(err);
449 } else if self.too_many_args_provided() {
450 self.suggest_removing_args_or_generics(err);
451 } else {
452 unreachable!();
453 }
454 }
455 }
5869c6ff
XL
456 }
457
458 /// Suggests to add missing argument(s) when current invocation site already contains some
459 /// generics:
460 ///
461 /// ```text
462 /// type Map = HashMap<String>;
463 /// ```
5e7ed085 464 fn suggest_adding_args(&self, err: &mut Diagnostic) {
5869c6ff
XL
465 if self.gen_args.parenthesized {
466 return;
467 }
468
17df50a5
XL
469 match self.gen_args_info {
470 MissingLifetimes { .. } => {
471 self.suggest_adding_lifetime_args(err);
472 }
473 MissingTypesOrConsts { .. } => {
474 self.suggest_adding_type_and_const_args(err);
475 }
476 _ => unreachable!(),
477 }
478 }
5869c6ff 479
5e7ed085 480 fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) {
17df50a5
XL
481 debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment);
482 let num_missing_args = self.num_missing_lifetime_args();
483 let num_params_to_take = num_missing_args;
484 let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
485
486 // we first try to get lifetime name suggestions from scope or elision information. If none is
5e7ed085 487 // available we use the parameter definitions
17df50a5
XL
488 let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
489 if let Some(lifetimes_in_scope) = self.tcx.lifetime_scope(hir_id) {
490 match lifetimes_in_scope {
491 LifetimeScopeForPath::NonElided(param_names) => {
492 debug!("NonElided(param_names: {:?})", param_names);
493
494 if param_names.len() >= num_params_to_take {
495 // use lifetime parameters in scope for suggestions
496 param_names
497 .iter()
498 .take(num_params_to_take)
499 .map(|p| (*p).clone())
500 .collect::<Vec<_>>()
501 .join(", ")
502 } else {
503 // Not enough lifetime arguments in scope -> create suggestions from
504 // lifetime parameter names in definition. An error for the incorrect
505 // lifetime scope will be output later.
506 self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
507 }
508 }
509 LifetimeScopeForPath::Elided => {
510 debug!("Elided");
511 // use suggestions of the form `<'_, '_>` in case lifetime can be elided
512 ["'_"].repeat(num_params_to_take).join(",")
513 }
514 }
515 } else {
516 self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
517 }
5869c6ff 518 } else {
17df50a5 519 self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
5869c6ff
XL
520 };
521
17df50a5 522 debug!("suggested_args: {:?}", &suggested_args);
5869c6ff 523
17df50a5
XL
524 match self.angle_brackets {
525 AngleBrackets::Missing => {
526 let span = self.path_segment.ident.span;
527
528 // insert a suggestion of the form "Y<'a, 'b>"
529 let ident = self.path_segment.ident.name.to_ident_string();
530 let sugg = format!("{}<{}>", ident, suggested_args);
531 debug!("sugg: {:?}", sugg);
532
533 err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
534 }
535
536 AngleBrackets::Available => {
537 let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 {
538 (self.gen_args.span().unwrap().shrink_to_lo(), true)
539 } else {
540 let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1];
541 (last_lt.span().shrink_to_hi(), false)
542 };
543 let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
544 let has_bindings = !self.gen_args.bindings.is_empty();
545
546 let sugg_prefix = if is_first { "" } else { ", " };
547 let sugg_suffix =
548 if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" };
5869c6ff 549
17df50a5
XL
550 let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
551 debug!("sugg: {:?}", sugg);
5869c6ff 552
17df50a5
XL
553 err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
554 }
555 AngleBrackets::Implied => {
556 // We never encounter missing lifetimes in situations in which lifetimes are elided
557 unreachable!();
558 }
559 }
560 }
561
5e7ed085 562 fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
17df50a5
XL
563 let num_missing_args = self.num_missing_type_or_const_args();
564 let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
565
566 let suggested_args =
567 self.get_type_or_const_args_suggestions_from_param_names(num_missing_args);
568 debug!("suggested_args: {:?}", suggested_args);
569
570 match self.angle_brackets {
571 AngleBrackets::Missing | AngleBrackets::Implied => {
572 let span = self.path_segment.ident.span;
573
574 // insert a suggestion of the form "Y<T, U>"
575 let ident = self.path_segment.ident.name.to_ident_string();
576 let sugg = format!("{}<{}>", ident, suggested_args);
577 debug!("sugg: {:?}", sugg);
578
579 err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
580 }
581 AngleBrackets::Available => {
582 let gen_args_span = self.gen_args.span().unwrap();
583 let sugg_offset =
584 self.get_lifetime_args_offset() + self.num_provided_type_or_const_args();
585
586 let (sugg_span, is_first) = if sugg_offset == 0 {
587 (gen_args_span.shrink_to_lo(), true)
588 } else {
589 let arg_span = self.gen_args.args[sugg_offset - 1].span();
5e7ed085 590 // If we came here then inferred lifetime's spans can only point
17df50a5
XL
591 // to either the opening bracket or to the space right after.
592 // Both of these spans have an `hi` lower than or equal to the span
593 // of the generics excluding the brackets.
594 // This allows us to check if `arg_span` is the artificial span of
595 // an inferred lifetime, in which case the generic we're suggesting to
596 // add will be the first visible, even if it isn't the actual first generic.
597 (arg_span.shrink_to_hi(), arg_span.hi() <= gen_args_span.lo())
598 };
599
600 let sugg_prefix = if is_first { "" } else { ", " };
601 let sugg_suffix =
602 if is_first && !self.gen_args.bindings.is_empty() { ", " } else { "" };
603
604 let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
605 debug!("sugg: {:?}", sugg);
606
607 err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
608 }
609 }
5869c6ff
XL
610 }
611
612 /// Suggests to remove redundant argument(s):
613 ///
614 /// ```text
615 /// type Map = HashMap<String, String, String, String>;
616 /// ```
5e7ed085 617 fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
17df50a5
XL
618 let num_provided_lt_args = self.num_provided_lifetime_args();
619 let num_provided_type_const_args = self.num_provided_type_or_const_args();
620 let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
621 assert!(num_provided_args > 0);
622
623 let num_redundant_lt_args = self.num_excess_lifetime_args();
624 let num_redundant_type_or_const_args = self.num_excess_type_or_const_args();
625 let num_redundant_args = num_redundant_lt_args + num_redundant_type_or_const_args;
626
627 let redundant_lifetime_args = num_redundant_lt_args > 0;
628 let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
629
630 let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
631
5e7ed085 632 let remove_lifetime_args = |err: &mut Diagnostic| {
17df50a5
XL
633 let mut lt_arg_spans = Vec::new();
634 let mut found_redundant = false;
635 for arg in self.gen_args.args {
636 if let hir::GenericArg::Lifetime(_) = arg {
637 lt_arg_spans.push(arg.span());
638 if lt_arg_spans.len() > self.num_expected_lifetime_args() {
639 found_redundant = true;
640 }
641 } else if found_redundant {
642 // Argument which is redundant and separated like this `'c`
643 // is not included to avoid including `Bar` in span.
644 // ```
645 // type Foo<'a, T> = &'a T;
646 // let _: Foo<'a, 'b, Bar, 'c>;
647 // ```
648 break;
649 }
650 }
651
652 let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
653 let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
654
655 let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
656 debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
657
658 let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
659 let msg_lifetimes = format!(
5e7ed085
FG
660 "remove {these} lifetime argument{s}",
661 these = pluralize!("this", num_redundant_lt_args),
662 s = pluralize!(num_redundant_lt_args),
17df50a5
XL
663 );
664
665 err.span_suggestion(
666 span_redundant_lt_args,
667 &msg_lifetimes,
668 String::new(),
669 Applicability::MaybeIncorrect,
670 );
671 };
672
5e7ed085 673 let remove_type_or_const_args = |err: &mut Diagnostic| {
17df50a5
XL
674 let mut gen_arg_spans = Vec::new();
675 let mut found_redundant = false;
676 for arg in self.gen_args.args {
677 match arg {
c295e0f8
XL
678 hir::GenericArg::Type(_)
679 | hir::GenericArg::Const(_)
680 | hir::GenericArg::Infer(_) => {
17df50a5
XL
681 gen_arg_spans.push(arg.span());
682 if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
683 found_redundant = true;
684 }
685 }
686 _ if found_redundant => break,
687 _ => {}
688 }
689 }
5869c6ff 690
17df50a5
XL
691 let span_lo_redundant_type_or_const_args =
692 gen_arg_spans[self.num_expected_type_or_const_args()];
693 let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
5869c6ff 694
17df50a5
XL
695 let span_redundant_type_or_const_args =
696 span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
697 debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
5869c6ff 698
17df50a5
XL
699 let num_redundant_gen_args =
700 gen_arg_spans.len() - self.num_expected_type_or_const_args();
701 let msg_types_or_consts = format!(
5e7ed085
FG
702 "remove {these} generic argument{s}",
703 these = pluralize!("this", num_redundant_gen_args),
704 s = pluralize!(num_redundant_gen_args),
17df50a5
XL
705 );
706
707 err.span_suggestion(
708 span_redundant_type_or_const_args,
709 &msg_types_or_consts,
710 String::new(),
711 Applicability::MaybeIncorrect,
712 );
713 };
714
715 if remove_entire_generics {
5869c6ff
XL
716 let span = self
717 .path_segment
718 .args
719 .unwrap()
17df50a5 720 .span_ext()
5869c6ff
XL
721 .unwrap()
722 .with_lo(self.path_segment.ident.span.hi());
723
724 let msg = format!(
725 "remove these {}generics",
726 if self.gen_args.parenthesized { "parenthetical " } else { "" },
727 );
728
17df50a5
XL
729 err.span_suggestion(span, &msg, String::new(), Applicability::MaybeIncorrect);
730 } else if redundant_lifetime_args && redundant_type_or_const_args {
731 remove_lifetime_args(err);
732 remove_type_or_const_args(err);
733 } else if redundant_lifetime_args {
734 remove_lifetime_args(err);
5869c6ff 735 } else {
17df50a5
XL
736 assert!(redundant_type_or_const_args);
737 remove_type_or_const_args(err);
738 }
5869c6ff
XL
739 }
740
741 /// Builds the `type defined here` message.
5e7ed085 742 fn show_definition(&self, err: &mut Diagnostic) {
5869c6ff 743 let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
c295e0f8
XL
744 if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
745 def_span.into()
746 } else {
747 return;
748 }
5869c6ff
XL
749 } else {
750 return;
751 };
752
753 let msg = {
754 let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
17df50a5 755 let (quantifier, bound) = self.get_quantifier_and_bound();
5869c6ff
XL
756
757 let params = if bound == 0 {
758 String::new()
759 } else {
760 let params = self
761 .gen_params
762 .params
763 .iter()
764 .skip(self.params_offset)
765 .take(bound)
766 .map(|param| {
767 let span = self.tcx.def_span(param.def_id);
768 spans.push_span_label(span, String::new());
769 param
770 })
771 .map(|param| format!("`{}`", param.name))
772 .collect::<Vec<_>>()
773 .join(", ");
774
775 format!(": {}", params)
776 };
777
778 format!(
779 "{} defined here, with {}{} {} parameter{}{}",
780 def_kind,
781 quantifier,
782 bound,
17df50a5 783 self.kind(),
5869c6ff
XL
784 pluralize!(bound),
785 params,
786 )
787 };
788
789 err.span_note(spans, &msg);
790 }
5e7ed085
FG
791
792 /// Add note if `impl Trait` is explicitly specified.
793 fn note_synth_provided(&self, err: &mut Diagnostic) {
794 if !self.is_synth_provided() {
795 return;
796 }
797
798 err.note("`impl Trait` cannot be explicitly specified as a generic argument");
799 }
5869c6ff
XL
800}
801
802impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
803 fn session(&self) -> &Session {
804 self.tcx.sess
805 }
806
807 fn code(&self) -> DiagnosticId {
808 rustc_errors::error_code!(E0107)
809 }
810
5e7ed085 811 fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
5869c6ff
XL
812 let mut err = self.start_diagnostics();
813
814 self.notify(&mut err);
815 self.suggest(&mut err);
816 self.show_definition(&mut err);
5e7ed085 817 self.note_synth_provided(&mut err);
5869c6ff
XL
818
819 err
820 }
821}