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