1use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2use rustc_data_structures::sorted_map::SortedMap;
3use rustc_data_structures::unord::UnordMap;
4use rustc_errors::codes::*;
5use rustc_errors::{
6 Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, pluralize,
7 struct_span_code_err,
8};
9use rustc_hir::def::{CtorOf, DefKind, Res};
10use rustc_hir::def_id::DefId;
11use rustc_hir::{self as hir, HirId};
12use rustc_middle::bug;
13use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
14use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
15use rustc_middle::ty::{
16 self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
17 suggest_constraining_type_param,
18};
19use rustc_session::parse::feature_err;
20use rustc_span::edit_distance::find_best_match_for_name;
21use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
22use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
23use rustc_trait_selection::traits::{
24 FulfillmentError, dyn_compatibility_violations_for_assoc_item,
25};
26use smallvec::SmallVec;
27use tracing::debug;
28
29use super::InherentAssocCandidate;
30use crate::errors::{
31 self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
32 ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
33};
34use crate::fluent_generated as fluent;
35use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
36
37impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
38 pub(crate) fn report_missing_type_params(
41 &self,
42 missing_type_params: Vec<Symbol>,
43 def_id: DefId,
44 span: Span,
45 empty_generic_args: bool,
46 ) {
47 if missing_type_params.is_empty() {
48 return;
49 }
50
51 self.dcx().emit_err(MissingTypeParams {
52 span,
53 def_span: self.tcx().def_span(def_id),
54 span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
55 missing_type_params,
56 empty_generic_args,
57 });
58 }
59
60 pub(crate) fn report_internal_fn_trait(
63 &self,
64 span: Span,
65 trait_def_id: DefId,
66 trait_segment: &'_ hir::PathSegment<'_>,
67 is_impl: bool,
68 ) {
69 if self.tcx().features().unboxed_closures() {
70 return;
71 }
72
73 let trait_def = self.tcx().trait_def(trait_def_id);
74 if !trait_def.paren_sugar {
75 if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar {
76 feature_err(
78 &self.tcx().sess,
79 sym::unboxed_closures,
80 span,
81 "parenthetical notation is only stable when used with `Fn`-family traits",
82 )
83 .emit();
84 }
85
86 return;
87 }
88
89 let sess = self.tcx().sess;
90
91 if trait_segment.args().parenthesized != hir::GenericArgsParentheses::ParenSugar {
92 let mut err = feature_err(
94 sess,
95 sym::unboxed_closures,
96 span,
97 "the precise format of `Fn`-family traits' type parameters is subject to change",
98 );
99 if !is_impl {
102 err.span_suggestion(
103 span,
104 "use parenthetical notation instead",
105 fn_trait_to_string(self.tcx(), trait_segment, true),
106 Applicability::MaybeIncorrect,
107 );
108 }
109 err.emit();
110 }
111
112 if is_impl {
113 let trait_name = self.tcx().def_path_str(trait_def_id);
114 self.dcx().emit_err(ManualImplementation { span, trait_name });
115 }
116 }
117
118 pub(super) fn report_unresolved_assoc_item<I>(
119 &self,
120 all_candidates: impl Fn() -> I,
121 qself: AssocItemQSelf,
122 assoc_tag: ty::AssocTag,
123 assoc_ident: Ident,
124 span: Span,
125 constraint: Option<&hir::AssocItemConstraint<'tcx>>,
126 ) -> ErrorGuaranteed
127 where
128 I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
129 {
130 let tcx = self.tcx();
131
132 if let Some(assoc_item) = all_candidates().find_map(|r| {
134 tcx.associated_items(r.def_id())
135 .filter_by_name_unhygienic(assoc_ident.name)
136 .find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id()))
137 }) {
138 return self.report_assoc_kind_mismatch(
139 assoc_item,
140 assoc_tag,
141 assoc_ident,
142 span,
143 constraint,
144 );
145 }
146
147 let assoc_kind_str = assoc_tag_str(assoc_tag);
148 let qself_str = qself.to_string(tcx);
149
150 let is_dummy = assoc_ident.span == DUMMY_SP;
153
154 let mut err = errors::AssocItemNotFound {
155 span: if is_dummy { span } else { assoc_ident.span },
156 assoc_ident,
157 assoc_kind: assoc_kind_str,
158 qself: &qself_str,
159 label: None,
160 sugg: None,
161 within_macro_span: assoc_ident.span.within_macro(span, tcx.sess.source_map()),
164 };
165
166 if is_dummy {
167 err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
168 return self.dcx().emit_err(err);
169 }
170
171 let all_candidate_names: Vec<_> = all_candidates()
172 .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
173 .filter_map(|item| {
174 if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
175 item.opt_name()
176 } else {
177 None
178 }
179 })
180 .collect();
181
182 if let Some(suggested_name) =
183 find_best_match_for_name(&all_candidate_names, assoc_ident.name, None)
184 {
185 err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
186 span: assoc_ident.span,
187 assoc_kind: assoc_kind_str,
188 suggested_name,
189 });
190 return self.dcx().emit_err(err);
191 }
192
193 let visible_traits: Vec<_> = tcx
198 .visible_traits()
199 .filter(|trait_def_id| {
200 let viz = tcx.visibility(*trait_def_id);
201 let def_id = self.item_def_id();
202 viz.is_accessible_from(def_id, tcx)
203 })
204 .collect();
205
206 let wider_candidate_names: Vec<_> = visible_traits
207 .iter()
208 .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
209 .filter_map(|item| {
210 (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
211 })
212 .collect();
213
214 if let Some(suggested_name) =
215 find_best_match_for_name(&wider_candidate_names, assoc_ident.name, None)
216 {
217 if let [best_trait] = visible_traits
218 .iter()
219 .copied()
220 .filter(|trait_def_id| {
221 tcx.associated_items(trait_def_id)
222 .filter_by_name_unhygienic(suggested_name)
223 .any(|item| item.as_tag() == assoc_tag)
224 })
225 .collect::<Vec<_>>()[..]
226 {
227 let trait_name = tcx.def_path_str(best_trait);
228 err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
229 span: assoc_ident.span,
230 assoc_kind: assoc_kind_str,
231 trait_name: &trait_name,
232 suggested_name,
233 identically_named: suggested_name == assoc_ident.name,
234 });
235 if let AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span) = qself
236 && let item_def_id =
240 tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
241 && let Some(generics) = tcx.hir_get_generics(item_def_id.def_id)
243 {
244 if generics
248 .bounds_for_param(ty_param_def_id)
249 .flat_map(|pred| pred.bounds.iter())
250 .any(|b| match b {
251 hir::GenericBound::Trait(t, ..) => {
252 t.trait_ref.trait_def_id() == Some(best_trait)
253 }
254 _ => false,
255 })
256 {
257 err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
260 span: assoc_ident.span,
261 trait_name: &trait_name,
262 assoc_kind: assoc_kind_str,
263 suggested_name,
264 });
265 return self.dcx().emit_err(err);
266 }
267
268 let trait_args = &ty::GenericArgs::identity_for_item(tcx, best_trait)[1..];
269 let mut trait_ref = trait_name.clone();
270 let applicability = if let [arg, args @ ..] = trait_args {
271 use std::fmt::Write;
272 write!(trait_ref, "</* {arg}").unwrap();
273 args.iter().try_for_each(|arg| write!(trait_ref, ", {arg}")).unwrap();
274 trait_ref += " */>";
275 Applicability::HasPlaceholders
276 } else {
277 Applicability::MaybeIncorrect
278 };
279
280 let identically_named = suggested_name == assoc_ident.name;
281
282 if let DefKind::TyAlias = tcx.def_kind(item_def_id)
283 && !tcx.type_alias_is_lazy(item_def_id)
284 {
285 err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTraitQPath {
286 lo: ty_param_span.shrink_to_lo(),
287 mi: ty_param_span.shrink_to_hi(),
288 hi: (!identically_named).then_some(assoc_ident.span),
289 trait_ref,
290 identically_named,
291 suggested_name,
292 applicability,
293 });
294 } else {
295 let mut err = self.dcx().create_err(err);
296 if suggest_constraining_type_param(
297 tcx,
298 generics,
299 &mut err,
300 &qself_str,
301 &trait_ref,
302 Some(best_trait),
303 None,
304 ) && !identically_named
305 {
306 err.span_suggestion_verbose(
309 assoc_ident.span,
310 fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
311 suggested_name,
312 Applicability::MaybeIncorrect,
313 );
314 }
315 return err.emit();
316 }
317 }
318 return self.dcx().emit_err(err);
319 }
320 }
321
322 if let [candidate_name] = all_candidate_names.as_slice() {
325 err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
326 span: assoc_ident.span,
327 qself: &qself_str,
328 assoc_kind: assoc_kind_str,
329 suggested_name: *candidate_name,
330 });
331 } else {
332 err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_ident.span });
333 }
334
335 self.dcx().emit_err(err)
336 }
337
338 fn report_assoc_kind_mismatch(
339 &self,
340 assoc_item: &ty::AssocItem,
341 assoc_tag: ty::AssocTag,
342 ident: Ident,
343 span: Span,
344 constraint: Option<&hir::AssocItemConstraint<'tcx>>,
345 ) -> ErrorGuaranteed {
346 let tcx = self.tcx();
347
348 let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
349 && let Some(constraint) = constraint
350 && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
351 {
352 let lo = if constraint.gen_args.span_ext.is_dummy() {
353 ident.span
354 } else {
355 constraint.gen_args.span_ext
356 };
357 Some(lo.between(span.shrink_to_hi()))
358 } else {
359 None
360 };
361
362 let wrap_in_braces_sugg = if let Some(constraint) = constraint
364 && let Some(hir_ty) = constraint.ty()
365 && let ty = self.lower_ty(hir_ty)
366 && (ty.is_enum() || ty.references_error())
367 && tcx.features().associated_const_equality()
368 {
369 Some(errors::AssocKindMismatchWrapInBracesSugg {
370 lo: hir_ty.span.shrink_to_lo(),
371 hi: hir_ty.span.shrink_to_hi(),
372 })
373 } else {
374 None
375 };
376
377 let (span, expected_because_label, expected, got) = if let Some(constraint) = constraint
380 && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
381 {
382 let span = match term {
383 hir::Term::Ty(ty) => ty.span,
384 hir::Term::Const(ct) => ct.span(),
385 };
386 (span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
387 } else {
388 (ident.span, None, assoc_tag, assoc_item.as_tag())
389 };
390
391 self.dcx().emit_err(errors::AssocKindMismatch {
392 span,
393 expected: assoc_tag_str(expected),
394 got: assoc_tag_str(got),
395 expected_because_label,
396 assoc_kind: assoc_tag_str(assoc_item.as_tag()),
397 def_span: tcx.def_span(assoc_item.def_id),
398 bound_on_assoc_const_label,
399 wrap_in_braces_sugg,
400 })
401 }
402
403 pub(crate) fn report_missing_self_ty_for_resolved_path(
404 &self,
405 trait_def_id: DefId,
406 span: Span,
407 item_segment: &hir::PathSegment<'tcx>,
408 assoc_tag: ty::AssocTag,
409 ) -> ErrorGuaranteed {
410 let tcx = self.tcx();
411 let path_str = tcx.def_path_str(trait_def_id);
412
413 let def_id = self.item_def_id();
414 debug!(item_def_id = ?def_id);
415
416 let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
418 debug!(?parent_def_id);
419
420 let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
423 let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
424
425 let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
426 vec!["Self".to_string()]
427 } else {
428 tcx.all_impls(trait_def_id)
430 .map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
431 .filter(|header| {
432 tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
434 && header.polarity != ty::ImplPolarity::Negative
435 })
436 .map(|header| header.trait_ref.instantiate_identity().self_ty())
437 .filter(|self_ty| !self_ty.has_non_region_param())
439 .map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string())
440 .collect()
441 };
442 self.report_ambiguous_assoc_item_path(
446 span,
447 &type_names,
448 &[path_str],
449 item_segment.ident,
450 assoc_tag,
451 )
452 }
453
454 pub(super) fn report_unresolved_type_relative_path(
455 &self,
456 self_ty: Ty<'tcx>,
457 hir_self_ty: &hir::Ty<'_>,
458 assoc_tag: ty::AssocTag,
459 ident: Ident,
460 qpath_hir_id: HirId,
461 span: Span,
462 variant_def_id: Option<DefId>,
463 ) -> ErrorGuaranteed {
464 let tcx = self.tcx();
465 let kind_str = assoc_tag_str(assoc_tag);
466 if variant_def_id.is_some() {
467 let msg = format!("expected {kind_str}, found variant `{ident}`");
469 self.dcx().span_err(span, msg)
470 } else if self_ty.is_enum() {
471 let mut err = self.dcx().create_err(errors::NoVariantNamed {
472 span: ident.span,
473 ident,
474 ty: self_ty,
475 });
476
477 let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
478 if let Some(variant_name) = find_best_match_for_name(
479 &adt_def.variants().iter().map(|variant| variant.name).collect::<Vec<Symbol>>(),
480 ident.name,
481 None,
482 ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == variant_name)
483 {
484 let mut suggestion = vec![(ident.span, variant_name.to_string())];
485 if let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(expr), .. })
486 | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
487 && let hir::ExprKind::Struct(..) = expr.kind
488 {
489 match variant.ctor {
490 None => {
491 suggestion = vec![(
493 ident.span.with_hi(expr.span.hi()),
494 if variant.fields.is_empty() {
495 format!("{variant_name} {{}}")
496 } else {
497 format!(
498 "{variant_name} {{ {} }}",
499 variant
500 .fields
501 .iter()
502 .map(|f| format!("{}: /* value */", f.name))
503 .collect::<Vec<_>>()
504 .join(", ")
505 )
506 },
507 )];
508 }
509 Some((hir::def::CtorKind::Fn, def_id)) => {
510 let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
512 let inputs = fn_sig.inputs().skip_binder();
513 suggestion = vec![(
514 ident.span.with_hi(expr.span.hi()),
515 format!(
516 "{variant_name}({})",
517 inputs
518 .iter()
519 .map(|i| format!("/* {i} */"))
520 .collect::<Vec<_>>()
521 .join(", ")
522 ),
523 )];
524 }
525 Some((hir::def::CtorKind::Const, _)) => {
526 suggestion = vec![(
528 ident.span.with_hi(expr.span.hi()),
529 variant_name.to_string(),
530 )];
531 }
532 }
533 }
534 err.multipart_suggestion_verbose(
535 "there is a variant with a similar name",
536 suggestion,
537 Applicability::HasPlaceholders,
538 );
539 } else {
540 err.span_label(ident.span, format!("variant not found in `{self_ty}`"));
541 }
542
543 if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
544 err.span_label(sp, format!("variant `{ident}` not found here"));
545 }
546
547 err.emit()
548 } else if let Err(reported) = self_ty.error_reported() {
549 reported
550 } else {
551 match self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty) {
552 Ok(()) => {}
553 Err(reported) => return reported,
554 }
555
556 let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
557
558 self.report_ambiguous_assoc_item_path(
559 span,
560 &[self_ty.to_string()],
561 &traits,
562 ident,
563 assoc_tag,
564 )
565 }
566 }
567
568 pub(super) fn report_ambiguous_assoc_item_path(
569 &self,
570 span: Span,
571 types: &[String],
572 traits: &[String],
573 ident: Ident,
574 assoc_tag: ty::AssocTag,
575 ) -> ErrorGuaranteed {
576 let kind_str = assoc_tag_str(assoc_tag);
577 let mut err =
578 struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
579 if self
580 .tcx()
581 .resolutions(())
582 .confused_type_with_std_module
583 .keys()
584 .any(|full_span| full_span.contains(span))
585 {
586 err.span_suggestion_verbose(
587 span.shrink_to_lo(),
588 "you are looking for the module in `std`, not the primitive type",
589 "std::",
590 Applicability::MachineApplicable,
591 );
592 } else {
593 let sugg_sp = span.until(ident.span);
594
595 let mut types = types.to_vec();
596 types.sort();
597 let mut traits = traits.to_vec();
598 traits.sort();
599 match (&types[..], &traits[..]) {
600 ([], []) => {
601 err.span_suggestion_verbose(
602 sugg_sp,
603 format!(
604 "if there were a type named `Type` that implements a trait named \
605 `Trait` with associated {kind_str} `{ident}`, you could use the \
606 fully-qualified path",
607 ),
608 "<Type as Trait>::",
609 Applicability::HasPlaceholders,
610 );
611 }
612 ([], [trait_str]) => {
613 err.span_suggestion_verbose(
614 sugg_sp,
615 format!(
616 "if there were a type named `Example` that implemented `{trait_str}`, \
617 you could use the fully-qualified path",
618 ),
619 format!("<Example as {trait_str}>::"),
620 Applicability::HasPlaceholders,
621 );
622 }
623 ([], traits) => {
624 err.span_suggestions_with_style(
625 sugg_sp,
626 format!(
627 "if there were a type named `Example` that implemented one of the \
628 traits with associated {kind_str} `{ident}`, you could use the \
629 fully-qualified path",
630 ),
631 traits.iter().map(|trait_str| format!("<Example as {trait_str}>::")),
632 Applicability::HasPlaceholders,
633 SuggestionStyle::ShowAlways,
634 );
635 }
636 ([type_str], []) => {
637 err.span_suggestion_verbose(
638 sugg_sp,
639 format!(
640 "if there were a trait named `Example` with associated {kind_str} `{ident}` \
641 implemented for `{type_str}`, you could use the fully-qualified path",
642 ),
643 format!("<{type_str} as Example>::"),
644 Applicability::HasPlaceholders,
645 );
646 }
647 (types, []) => {
648 err.span_suggestions_with_style(
649 sugg_sp,
650 format!(
651 "if there were a trait named `Example` with associated {kind_str} `{ident}` \
652 implemented for one of the types, you could use the fully-qualified \
653 path",
654 ),
655 types
656 .into_iter()
657 .map(|type_str| format!("<{type_str} as Example>::")),
658 Applicability::HasPlaceholders,
659 SuggestionStyle::ShowAlways,
660 );
661 }
662 (types, traits) => {
663 let mut suggestions = vec![];
664 for type_str in types {
665 for trait_str in traits {
666 suggestions.push(format!("<{type_str} as {trait_str}>::"));
667 }
668 }
669 err.span_suggestions_with_style(
670 sugg_sp,
671 "use fully-qualified syntax",
672 suggestions,
673 Applicability::MachineApplicable,
674 SuggestionStyle::ShowAlways,
675 );
676 }
677 }
678 }
679 err.emit()
680 }
681
682 pub(crate) fn report_ambiguous_inherent_assoc_item(
683 &self,
684 name: Ident,
685 candidates: Vec<DefId>,
686 span: Span,
687 ) -> ErrorGuaranteed {
688 let mut err = struct_span_code_err!(
689 self.dcx(),
690 name.span,
691 E0034,
692 "multiple applicable items in scope"
693 );
694 err.span_label(name.span, format!("multiple `{name}` found"));
695 self.note_ambiguous_inherent_assoc_item(&mut err, candidates, span);
696 err.emit()
697 }
698
699 fn note_ambiguous_inherent_assoc_item(
701 &self,
702 err: &mut Diag<'_>,
703 candidates: Vec<DefId>,
704 span: Span,
705 ) {
706 let tcx = self.tcx();
707
708 let limit = if candidates.len() == 5 { 5 } else { 4 };
710
711 for (index, &item) in candidates.iter().take(limit).enumerate() {
712 let impl_ = tcx.parent(item);
713
714 let note_span = if item.is_local() {
715 Some(tcx.def_span(item))
716 } else if impl_.is_local() {
717 Some(tcx.def_span(impl_))
718 } else {
719 None
720 };
721
722 let title = if candidates.len() > 1 {
723 format!("candidate #{}", index + 1)
724 } else {
725 "the candidate".into()
726 };
727
728 let impl_ty = tcx.at(span).type_of(impl_).instantiate_identity();
729 let note = format!("{title} is defined in an impl for the type `{impl_ty}`");
730
731 if let Some(span) = note_span {
732 err.span_note(span, note);
733 } else {
734 err.note(note);
735 }
736 }
737 if candidates.len() > limit {
738 err.note(format!("and {} others", candidates.len() - limit));
739 }
740 }
741
742 pub(crate) fn report_unresolved_inherent_assoc_item(
744 &self,
745 name: Ident,
746 self_ty: Ty<'tcx>,
747 candidates: Vec<InherentAssocCandidate>,
748 fulfillment_errors: Vec<FulfillmentError<'tcx>>,
749 span: Span,
750 assoc_tag: ty::AssocTag,
751 ) -> ErrorGuaranteed {
752 let tcx = self.tcx();
759
760 let assoc_tag_str = assoc_tag_str(assoc_tag);
761 let adt_did = self_ty.ty_adt_def().map(|def| def.did());
762 let add_def_label = |err: &mut Diag<'_>| {
763 if let Some(did) = adt_did {
764 err.span_label(
765 tcx.def_span(did),
766 format!(
767 "associated {assoc_tag_str} `{name}` not found for this {}",
768 tcx.def_descr(did)
769 ),
770 );
771 }
772 };
773
774 if fulfillment_errors.is_empty() {
775 let limit = if candidates.len() == 5 { 5 } else { 4 };
778 let type_candidates = candidates
779 .iter()
780 .take(limit)
781 .map(|cand| {
782 format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity())
783 })
784 .collect::<Vec<_>>()
785 .join("\n");
786 let additional_types = if candidates.len() > limit {
787 format!("\nand {} more types", candidates.len() - limit)
788 } else {
789 String::new()
790 };
791
792 let mut err = struct_span_code_err!(
793 self.dcx(),
794 name.span,
795 E0220,
796 "associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
797 );
798 err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
799 err.note(format!(
800 "the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
801 ));
802 add_def_label(&mut err);
803 return err.emit();
804 }
805
806 let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
807
808 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
809 let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
810 match self_ty.kind() {
811 ty::Adt(def, _) => {
813 bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
814 }
815 ty::Dynamic(preds, _) => {
817 for pred in preds.iter() {
818 match pred.skip_binder() {
819 ty::ExistentialPredicate::Trait(tr) => {
820 bound_spans
821 .get_mut_or_insert_default(tcx.def_span(tr.def_id))
822 .push(msg.clone());
823 }
824 ty::ExistentialPredicate::Projection(_)
825 | ty::ExistentialPredicate::AutoTrait(_) => {}
826 }
827 }
828 }
829 ty::Closure(def_id, _) => {
831 bound_spans
832 .get_mut_or_insert_default(tcx.def_span(*def_id))
833 .push(format!("`{quiet}`"));
834 }
835 _ => {}
836 }
837 };
838
839 let format_pred = |pred: ty::Predicate<'tcx>| {
840 let bound_predicate = pred.kind();
841 match bound_predicate.skip_binder() {
842 ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
843 let projection_term = pred.projection_term;
845 let quiet_projection_term = projection_term
846 .with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
847
848 let term = pred.term;
849 let obligation = format!("{projection_term} = {term}");
850 let quiet = format!("{quiet_projection_term} = {term}");
851
852 bound_span_label(projection_term.self_ty(), &obligation, &quiet);
853 Some((obligation, projection_term.self_ty()))
854 }
855 ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
856 let p = poly_trait_ref.trait_ref;
857 let self_ty = p.self_ty();
858 let path = p.print_only_trait_path();
859 let obligation = format!("{self_ty}: {path}");
860 let quiet = format!("_: {path}");
861 bound_span_label(self_ty, &obligation, &quiet);
862 Some((obligation, self_ty))
863 }
864 _ => None,
865 }
866 };
867
868 let mut bounds: Vec<_> = fulfillment_errors
871 .into_iter()
872 .map(|error| error.root_obligation.predicate)
873 .filter_map(format_pred)
874 .map(|(p, _)| format!("`{p}`"))
875 .collect();
876 bounds.sort();
877 bounds.dedup();
878
879 let mut err = self.dcx().struct_span_err(
880 name.span,
881 format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
882 );
883 if !bounds.is_empty() {
884 err.note(format!(
885 "the following trait bounds were not satisfied:\n{}",
886 bounds.join("\n")
887 ));
888 }
889 err.span_label(
890 name.span,
891 format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
892 );
893
894 for (span, mut bounds) in bound_spans {
895 if !tcx.sess.source_map().is_span_accessible(span) {
896 continue;
897 }
898 bounds.sort();
899 bounds.dedup();
900 let msg = match &bounds[..] {
901 [bound] => format!("doesn't satisfy {bound}"),
902 bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()),
903 [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")),
904 [] => unreachable!(),
905 };
906 err.span_label(span, msg);
907 }
908 add_def_label(&mut err);
909 err.emit()
910 }
911
912 pub(crate) fn check_for_required_assoc_tys(
917 &self,
918 spans: SmallVec<[Span; 1]>,
919 missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
920 potential_assoc_types: Vec<usize>,
921 trait_bounds: &[hir::PolyTraitRef<'_>],
922 ) -> Result<(), ErrorGuaranteed> {
923 if missing_assoc_types.is_empty() {
924 return Ok(());
925 }
926
927 let principal_span = *spans.first().unwrap();
928
929 let tcx = self.tcx();
930 let missing_assoc_types: Vec<_> = missing_assoc_types
932 .into_iter()
933 .map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
934 .collect();
935 let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
936 let mut names_len = 0;
937
938 let mut dyn_compatibility_violations = Ok(());
941 for (assoc_item, trait_ref) in &missing_assoc_types {
942 names.entry(trait_ref).or_default().push(assoc_item.name());
943 names_len += 1;
944
945 let violations =
946 dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
947 if !violations.is_empty() {
948 dyn_compatibility_violations = Err(report_dyn_incompatibility(
949 tcx,
950 principal_span,
951 None,
952 trait_ref.def_id(),
953 &violations,
954 )
955 .emit());
956 }
957 }
958
959 if let Err(guar) = dyn_compatibility_violations {
960 return Err(guar);
961 }
962
963 let mut in_expr_or_pat = false;
965 if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
966 let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
967 in_expr_or_pat = match grandparent {
968 hir::Node::Expr(_) | hir::Node::Pat(_) => true,
969 _ => false,
970 };
971 }
972
973 let bound_names = trait_bounds
978 .iter()
979 .filter_map(|poly_trait_ref| {
980 let path = poly_trait_ref.trait_ref.path.segments.last()?;
981 let args = path.args?;
982
983 Some(args.constraints.iter().filter_map(|constraint| {
984 let ident = constraint.ident;
985
986 let Res::Def(DefKind::Trait, trait_def) = path.res else {
987 return None;
988 };
989
990 let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
991 tcx,
992 ident,
993 ty::AssocTag::Type,
994 trait_def,
995 );
996
997 Some((ident.name, assoc_item?))
998 }))
999 })
1000 .flatten()
1001 .collect::<UnordMap<Symbol, &ty::AssocItem>>();
1002
1003 let mut names = names
1004 .into_iter()
1005 .map(|(trait_, mut assocs)| {
1006 assocs.sort();
1007 let trait_ = trait_.print_trait_sugared();
1008 format!(
1009 "{} in `{trait_}`",
1010 listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
1011 )
1012 })
1013 .collect::<Vec<String>>();
1014 names.sort();
1015 let names = names.join(", ");
1016
1017 let mut err = struct_span_code_err!(
1018 self.dcx(),
1019 principal_span,
1020 E0191,
1021 "the value of the associated type{} {} must be specified",
1022 pluralize!(names_len),
1023 names,
1024 );
1025 let mut suggestions = vec![];
1026 let mut types_count = 0;
1027 let mut where_constraints = vec![];
1028 let mut already_has_generics_args_suggestion = false;
1029
1030 let mut names: UnordMap<_, usize> = Default::default();
1031 for (item, _) in &missing_assoc_types {
1032 types_count += 1;
1033 *names.entry(item.name()).or_insert(0) += 1;
1034 }
1035 let mut dupes = false;
1036 let mut shadows = false;
1037 for (item, trait_ref) in &missing_assoc_types {
1038 let name = item.name();
1039 let prefix = if names[&name] > 1 {
1040 let trait_def_id = trait_ref.def_id();
1041 dupes = true;
1042 format!("{}::", tcx.def_path_str(trait_def_id))
1043 } else if bound_names.get(&name).is_some_and(|x| *x != item) {
1044 let trait_def_id = trait_ref.def_id();
1045 shadows = true;
1046 format!("{}::", tcx.def_path_str(trait_def_id))
1047 } else {
1048 String::new()
1049 };
1050
1051 let mut is_shadowed = false;
1052
1053 if let Some(assoc_item) = bound_names.get(&name)
1054 && *assoc_item != item
1055 {
1056 is_shadowed = true;
1057
1058 let rename_message =
1059 if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
1060 err.span_label(
1061 tcx.def_span(assoc_item.def_id),
1062 format!("`{}{}` shadowed here{}", prefix, name, rename_message),
1063 );
1064 }
1065
1066 let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
1067
1068 if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
1069 err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
1070 }
1071 }
1072 if potential_assoc_types.len() == missing_assoc_types.len() {
1073 already_has_generics_args_suggestion = true;
1077 } else if let (Ok(snippet), false, false) =
1078 (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
1079 {
1080 let types: Vec<_> = missing_assoc_types
1081 .iter()
1082 .map(|(item, _)| format!("{} = Type", item.name()))
1083 .collect();
1084 let code = if let Some(snippet) = snippet.strip_suffix('>') {
1085 format!("{}, {}>", snippet, types.join(", "))
1090 } else if in_expr_or_pat {
1091 format!("{}::<{}>", snippet, types.join(", "))
1094 } else {
1095 format!("{}<{}>", snippet, types.join(", "))
1098 };
1099 suggestions.push((principal_span, code));
1100 } else if dupes {
1101 where_constraints.push(principal_span);
1102 }
1103
1104 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
1105 using the fully-qualified path to the associated types";
1106 if !where_constraints.is_empty() && suggestions.is_empty() {
1107 err.help(where_msg);
1111 }
1112 if suggestions.len() != 1 || already_has_generics_args_suggestion {
1113 let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
1115 for (item, _) in &missing_assoc_types {
1116 types_count += 1;
1117 *names.entry(item.name()).or_insert(0) += 1;
1118 }
1119 let mut label = vec![];
1120 for (item, trait_ref) in &missing_assoc_types {
1121 let name = item.name();
1122 let postfix = if names[&name] > 1 {
1123 format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
1124 } else {
1125 String::new()
1126 };
1127 label.push(format!("`{}`{}", name, postfix));
1128 }
1129 if !label.is_empty() {
1130 err.span_label(
1131 principal_span,
1132 format!(
1133 "associated type{} {} must be specified",
1134 pluralize!(label.len()),
1135 label.join(", "),
1136 ),
1137 );
1138 }
1139 }
1140 suggestions.sort_by_key(|&(span, _)| span);
1141 let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
1154 if !suggestions.is_empty() && !overlaps {
1155 err.multipart_suggestion(
1156 format!("specify the associated type{}", pluralize!(types_count)),
1157 suggestions,
1158 Applicability::HasPlaceholders,
1159 );
1160 if !where_constraints.is_empty() {
1161 err.span_help(where_constraints, where_msg);
1162 }
1163 }
1164
1165 Err(err.emit())
1166 }
1167
1168 pub(crate) fn maybe_report_similar_assoc_fn(
1172 &self,
1173 span: Span,
1174 qself_ty: Ty<'tcx>,
1175 qself: &hir::Ty<'_>,
1176 ) -> Result<(), ErrorGuaranteed> {
1177 let tcx = self.tcx();
1178 if let Some((_, node)) = tcx.hir_parent_iter(qself.hir_id).skip(1).next()
1179 && let hir::Node::Expr(hir::Expr {
1180 kind:
1181 hir::ExprKind::Path(hir::QPath::TypeRelative(
1182 hir::Ty {
1183 kind:
1184 hir::TyKind::Path(hir::QPath::TypeRelative(
1185 _,
1186 hir::PathSegment { ident: ident2, .. },
1187 )),
1188 ..
1189 },
1190 hir::PathSegment { ident: ident3, .. },
1191 )),
1192 ..
1193 }) = node
1194 && let Some(inherent_impls) = qself_ty
1195 .ty_adt_def()
1196 .map(|adt_def| tcx.inherent_impls(adt_def.did()))
1197 .or_else(|| {
1198 simplify_type(tcx, qself_ty, TreatParams::InstantiateWithInfer)
1199 .map(|simple_ty| tcx.incoherent_impls(simple_ty))
1200 })
1201 && let name = Symbol::intern(&format!("{ident2}_{ident3}"))
1202 && let Some(item) = inherent_impls
1203 .iter()
1204 .flat_map(|inherent_impl| {
1205 tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
1206 })
1207 .next()
1208 && item.is_fn()
1209 {
1210 Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
1211 .with_span_suggestion_verbose(
1212 ident2.span.to(ident3.span),
1213 format!("there is an associated function with a similar name: `{name}`"),
1214 name,
1215 Applicability::MaybeIncorrect,
1216 )
1217 .emit())
1218 } else {
1219 Ok(())
1220 }
1221 }
1222
1223 pub fn report_prohibited_generic_args<'a>(
1224 &self,
1225 segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1226 args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
1227 err_extend: GenericsArgsErrExtend<'a>,
1228 ) -> ErrorGuaranteed {
1229 #[derive(PartialEq, Eq, Hash)]
1230 enum ProhibitGenericsArg {
1231 Lifetime,
1232 Type,
1233 Const,
1234 Infer,
1235 }
1236
1237 let mut prohibit_args = FxIndexSet::default();
1238 args_visitors.for_each(|arg| {
1239 match arg {
1240 hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
1241 hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
1242 hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
1243 hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
1244 };
1245 });
1246
1247 let segments: Vec<_> = segments.collect();
1248 let types_and_spans: Vec<_> = segments
1249 .iter()
1250 .flat_map(|segment| {
1251 if segment.args().args.is_empty() {
1252 None
1253 } else {
1254 Some((
1255 match segment.res {
1256 Res::PrimTy(ty) => {
1257 format!("{} `{}`", segment.res.descr(), ty.name())
1258 }
1259 Res::Def(_, def_id)
1260 if let Some(name) = self.tcx().opt_item_name(def_id) =>
1261 {
1262 format!("{} `{name}`", segment.res.descr())
1263 }
1264 Res::Err => "this type".to_string(),
1265 _ => segment.res.descr().to_string(),
1266 },
1267 segment.ident.span,
1268 ))
1269 }
1270 })
1271 .collect();
1272 let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
1273 .expect("expected one segment to deny");
1274
1275 let arg_spans: Vec<Span> =
1276 segments.iter().flat_map(|segment| segment.args().args).map(|arg| arg.span()).collect();
1277
1278 let mut kinds = Vec::with_capacity(4);
1279 prohibit_args.iter().for_each(|arg| match arg {
1280 ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
1281 ProhibitGenericsArg::Type => kinds.push("type"),
1282 ProhibitGenericsArg::Const => kinds.push("const"),
1283 ProhibitGenericsArg::Infer => kinds.push("generic"),
1284 });
1285
1286 let s = pluralize!(kinds.len());
1287 let kind =
1288 listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit");
1289 let last_span = *arg_spans.last().unwrap();
1290 let span: MultiSpan = arg_spans.into();
1291 let mut err = struct_span_code_err!(
1292 self.dcx(),
1293 span,
1294 E0109,
1295 "{kind} arguments are not allowed on {this_type}",
1296 );
1297 err.span_label(last_span, format!("{kind} argument{s} not allowed"));
1298 for (what, span) in types_and_spans {
1299 err.span_label(span, format!("not allowed on {what}"));
1300 }
1301 generics_args_err_extend(self.tcx(), segments.into_iter(), &mut err, err_extend);
1302 err.emit()
1303 }
1304
1305 pub fn report_trait_object_addition_traits(
1306 &self,
1307 regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
1308 ) -> ErrorGuaranteed {
1309 let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap();
1312 let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap();
1313 let mut err = struct_span_code_err!(
1314 self.dcx(),
1315 *regular_traits[1].1.first().unwrap(),
1316 E0225,
1317 "only auto traits can be used as additional traits in a trait object"
1318 );
1319 err.span_label(first_span, "first non-auto trait");
1320 for &alias_span in first_alias_spans {
1321 err.span_label(alias_span, "first non-auto trait comes from this alias");
1322 }
1323 err.span_label(second_span, "additional non-auto trait");
1324 for &alias_span in second_alias_spans {
1325 err.span_label(alias_span, "second non-auto trait comes from this alias");
1326 }
1327 err.help(format!(
1328 "consider creating a new trait with all of these as supertraits and using that \
1329 trait here instead: `trait NewTrait: {} {{}}`",
1330 regular_traits
1331 .iter()
1332 .map(|(pred, _)| pred
1334 .map_bound(|pred| pred.trait_ref)
1335 .print_only_trait_path()
1336 .to_string())
1337 .collect::<Vec<_>>()
1338 .join(" + "),
1339 ));
1340 err.note(
1341 "auto-traits like `Send` and `Sync` are traits that have special properties; \
1342 for more information on them, visit \
1343 <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
1344 );
1345 err.emit()
1346 }
1347
1348 pub fn report_trait_object_with_no_traits(
1349 &self,
1350 span: Span,
1351 user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
1352 ) -> ErrorGuaranteed {
1353 let tcx = self.tcx();
1354 let trait_alias_span = user_written_clauses
1355 .into_iter()
1356 .filter_map(|(clause, _)| clause.as_trait_clause())
1357 .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id()))
1358 .map(|trait_ref| tcx.def_span(trait_ref.def_id()));
1359
1360 self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
1361 }
1362}
1363
1364pub fn prohibit_assoc_item_constraint(
1366 cx: &dyn HirTyLowerer<'_>,
1367 constraint: &hir::AssocItemConstraint<'_>,
1368 segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
1369) -> ErrorGuaranteed {
1370 let tcx = cx.tcx();
1371 let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
1372 span: constraint.span,
1373 fn_trait_expansion: if let Some((_, segment, span)) = segment
1374 && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
1375 {
1376 Some(ParenthesizedFnTraitExpansion {
1377 span,
1378 expanded_type: fn_trait_to_string(tcx, segment, false),
1379 })
1380 } else {
1381 None
1382 },
1383 });
1384
1385 if let Some((def_id, segment, _)) = segment
1389 && segment.args().parenthesized == hir::GenericArgsParentheses::No
1390 {
1391 let suggest_removal = |e: &mut Diag<'_>| {
1393 let constraints = segment.args().constraints;
1394 let args = segment.args().args;
1395
1396 let Some(index) = constraints.iter().position(|b| b.hir_id == constraint.hir_id) else {
1408 bug!("a type binding exists but its HIR ID not found in generics");
1409 };
1410
1411 let preceding_span = if index > 0 {
1412 Some(constraints[index - 1].span)
1413 } else {
1414 args.last().map(|a| a.span())
1415 };
1416
1417 let next_span = constraints.get(index + 1).map(|constraint| constraint.span);
1418
1419 let removal_span = match (preceding_span, next_span) {
1420 (Some(prec), _) => constraint.span.with_lo(prec.hi()),
1421 (None, Some(next)) => constraint.span.with_hi(next.lo()),
1422 (None, None) => {
1423 let Some(generics_span) = segment.args().span_ext() else {
1424 bug!("a type binding exists but generic span is empty");
1425 };
1426
1427 generics_span
1428 }
1429 };
1430
1431 e.span_suggestion_verbose(
1433 removal_span,
1434 format!("consider removing this associated item {}", constraint.kind.descr()),
1435 "",
1436 Applicability::MaybeIncorrect,
1437 );
1438 };
1439
1440 let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
1443 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
1444 e.span_suggestion_verbose(
1445 constraint.span,
1446 format!("to use `{snippet}` as a generic argument specify it directly"),
1447 snippet,
1448 Applicability::MaybeIncorrect,
1449 );
1450 }
1451 };
1452
1453 let generics = tcx.generics_of(def_id);
1456 let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name);
1457
1458 if let Some(matching_param) = matching_param {
1460 match (constraint.kind, &matching_param.kind) {
1461 (
1462 hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) },
1463 GenericParamDefKind::Type { .. },
1464 ) => suggest_direct_use(&mut err, ty.span),
1465 (
1466 hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
1467 GenericParamDefKind::Const { .. },
1468 ) => {
1469 suggest_direct_use(&mut err, c.span());
1470 }
1471 (hir::AssocItemConstraintKind::Bound { bounds }, _) => {
1472 let impl_block = tcx
1478 .hir_parent_iter(constraint.hir_id)
1479 .find_map(|(_, node)| node.impl_block_of_trait(def_id));
1480
1481 let type_with_constraints =
1482 tcx.sess.source_map().span_to_snippet(constraint.span);
1483
1484 if let Some(impl_block) = impl_block
1485 && let Ok(type_with_constraints) = type_with_constraints
1486 {
1487 let lifetimes: String = bounds
1490 .iter()
1491 .filter_map(|bound| {
1492 if let hir::GenericBound::Outlives(lifetime) = bound {
1493 Some(format!("{lifetime}, "))
1494 } else {
1495 None
1496 }
1497 })
1498 .collect();
1499 let param_decl = if let Some(param_span) =
1502 impl_block.generics.span_for_param_suggestion()
1503 {
1504 (param_span, format!(", {lifetimes}{type_with_constraints}"))
1505 } else {
1506 (
1507 impl_block.generics.span.shrink_to_lo(),
1508 format!("<{lifetimes}{type_with_constraints}>"),
1509 )
1510 };
1511 let suggestions = vec![
1512 param_decl,
1513 (constraint.span.with_lo(constraint.ident.span.hi()), String::new()),
1514 ];
1515
1516 err.multipart_suggestion_verbose(
1517 "declare the type parameter right after the `impl` keyword",
1518 suggestions,
1519 Applicability::MaybeIncorrect,
1520 );
1521 }
1522 }
1523 _ => suggest_removal(&mut err),
1524 }
1525 } else {
1526 suggest_removal(&mut err);
1527 }
1528 }
1529
1530 err.emit()
1531}
1532
1533pub(crate) fn fn_trait_to_string(
1534 tcx: TyCtxt<'_>,
1535 trait_segment: &hir::PathSegment<'_>,
1536 parenthesized: bool,
1537) -> String {
1538 let args = trait_segment
1539 .args
1540 .and_then(|args| args.args.first())
1541 .and_then(|arg| match arg {
1542 hir::GenericArg::Type(ty) => match ty.kind {
1543 hir::TyKind::Tup(t) => t
1544 .iter()
1545 .map(|e| tcx.sess.source_map().span_to_snippet(e.span))
1546 .collect::<Result<Vec<_>, _>>()
1547 .map(|a| a.join(", ")),
1548 _ => tcx.sess.source_map().span_to_snippet(ty.span),
1549 }
1550 .map(|s| {
1551 if parenthesized || s.is_empty() { format!("({s})") } else { format!("({s},)") }
1553 })
1554 .ok(),
1555 _ => None,
1556 })
1557 .unwrap_or_else(|| "()".to_string());
1558
1559 let ret = trait_segment
1560 .args()
1561 .constraints
1562 .iter()
1563 .find_map(|c| {
1564 if c.ident.name == sym::Output
1565 && let Some(ty) = c.ty()
1566 && ty.span != tcx.hir_span(trait_segment.hir_id)
1567 {
1568 tcx.sess.source_map().span_to_snippet(ty.span).ok()
1569 } else {
1570 None
1571 }
1572 })
1573 .unwrap_or_else(|| "()".to_string());
1574
1575 if parenthesized {
1576 format!("{}{} -> {}", trait_segment.ident, args, ret)
1577 } else {
1578 format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
1579 }
1580}
1581
1582pub enum GenericsArgsErrExtend<'tcx> {
1584 EnumVariant {
1585 qself: &'tcx hir::Ty<'tcx>,
1586 assoc_segment: &'tcx hir::PathSegment<'tcx>,
1587 adt_def: AdtDef<'tcx>,
1588 },
1589 OpaqueTy,
1590 PrimTy(hir::PrimTy),
1591 SelfTyAlias {
1592 def_id: DefId,
1593 span: Span,
1594 },
1595 SelfTyParam(Span),
1596 Param(DefId),
1597 DefVariant(&'tcx [hir::PathSegment<'tcx>]),
1598 None,
1599}
1600
1601fn generics_args_err_extend<'a>(
1602 tcx: TyCtxt<'_>,
1603 segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1604 err: &mut Diag<'_>,
1605 err_extend: GenericsArgsErrExtend<'a>,
1606) {
1607 match err_extend {
1608 GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
1609 err.note("enum variants can't have type parameters");
1610 let type_name = tcx.item_name(adt_def.did());
1611 let msg = format!(
1612 "you might have meant to specify type parameters on enum \
1613 `{type_name}`"
1614 );
1615 let Some(args) = assoc_segment.args else {
1616 return;
1617 };
1618 let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
1623 if tcx.generics_of(adt_def.did()).is_empty() {
1624 err.span_suggestion_verbose(
1627 args_span,
1628 format!("{type_name} doesn't have generic parameters"),
1629 "",
1630 Applicability::MachineApplicable,
1631 );
1632 return;
1633 }
1634 let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
1635 err.note(msg);
1636 return;
1637 };
1638 let (qself_sugg_span, is_self) =
1639 if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1640 match &path.segments {
1643 [
1647 ..,
1648 hir::PathSegment {
1649 ident, args, res: Res::Def(DefKind::Enum, _), ..
1650 },
1651 _,
1652 ] => (
1653 ident
1656 .span
1657 .shrink_to_hi()
1658 .to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
1659 false,
1660 ),
1661 [segment] => {
1662 (
1663 segment.ident.span.shrink_to_hi().to(segment
1666 .args
1667 .map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
1668 kw::SelfUpper == segment.ident.name,
1669 )
1670 }
1671 _ => {
1672 err.note(msg);
1673 return;
1674 }
1675 }
1676 } else {
1677 err.note(msg);
1678 return;
1679 };
1680 let suggestion = vec![
1681 if is_self {
1682 (qself.span, format!("{type_name}{snippet}"))
1686 } else {
1687 (qself_sugg_span, snippet)
1688 },
1689 (args_span, String::new()),
1690 ];
1691 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
1692 }
1693 GenericsArgsErrExtend::DefVariant(segments) => {
1694 let args: Vec<Span> = segments
1695 .iter()
1696 .filter_map(|segment| match segment.res {
1697 Res::Def(
1698 DefKind::Ctor(CtorOf::Variant, _) | DefKind::Variant | DefKind::Enum,
1699 _,
1700 ) => segment.args().span_ext().map(|s| s.with_lo(segment.ident.span.hi())),
1701 _ => None,
1702 })
1703 .collect();
1704 if args.len() > 1
1705 && let Some(span) = args.into_iter().next_back()
1706 {
1707 err.note(
1708 "generic arguments are not allowed on both an enum and its variant's path \
1709 segments simultaneously; they are only valid in one place or the other",
1710 );
1711 err.span_suggestion_verbose(
1712 span,
1713 "remove the generics arguments from one of the path segments",
1714 String::new(),
1715 Applicability::MaybeIncorrect,
1716 );
1717 }
1718 }
1719 GenericsArgsErrExtend::PrimTy(prim_ty) => {
1720 let name = prim_ty.name_str();
1721 for segment in segments {
1722 if let Some(args) = segment.args {
1723 err.span_suggestion_verbose(
1724 segment.ident.span.shrink_to_hi().to(args.span_ext),
1725 format!("primitive type `{name}` doesn't have generic parameters"),
1726 "",
1727 Applicability::MaybeIncorrect,
1728 );
1729 }
1730 }
1731 }
1732 GenericsArgsErrExtend::OpaqueTy => {
1733 err.note("`impl Trait` types can't have type parameters");
1734 }
1735 GenericsArgsErrExtend::Param(def_id) => {
1736 let span = tcx.def_ident_span(def_id).unwrap();
1737 let kind = tcx.def_descr(def_id);
1738 let name = tcx.item_name(def_id);
1739 err.span_note(span, format!("{kind} `{name}` defined here"));
1740 }
1741 GenericsArgsErrExtend::SelfTyParam(span) => {
1742 err.span_suggestion_verbose(
1743 span,
1744 "the `Self` type doesn't accept type parameters",
1745 "",
1746 Applicability::MaybeIncorrect,
1747 );
1748 }
1749 GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
1750 let ty = tcx.at(span).type_of(def_id).instantiate_identity();
1751 let span_of_impl = tcx.span_of_impl(def_id);
1752 let def_id = match *ty.kind() {
1753 ty::Adt(self_def, _) => self_def.did(),
1754 _ => return,
1755 };
1756
1757 let type_name = tcx.item_name(def_id);
1758 let span_of_ty = tcx.def_ident_span(def_id);
1759 let generics = tcx.generics_of(def_id).count();
1760
1761 let msg = format!("`Self` is of type `{ty}`");
1762 if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
1763 let mut span: MultiSpan = vec![t_sp].into();
1764 span.push_span_label(
1765 i_sp,
1766 format!("`Self` is on type `{type_name}` in this `impl`"),
1767 );
1768 let mut postfix = "";
1769 if generics == 0 {
1770 postfix = ", which doesn't have generic parameters";
1771 }
1772 span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
1773 err.span_note(span, msg);
1774 } else {
1775 err.note(msg);
1776 }
1777 for segment in segments {
1778 if let Some(args) = segment.args
1779 && segment.ident.name == kw::SelfUpper
1780 {
1781 if generics == 0 {
1782 err.span_suggestion_verbose(
1785 segment.ident.span.shrink_to_hi().to(args.span_ext),
1786 "the `Self` type doesn't accept type parameters",
1787 "",
1788 Applicability::MachineApplicable,
1789 );
1790 return;
1791 } else {
1792 err.span_suggestion_verbose(
1793 segment.ident.span,
1794 format!(
1795 "the `Self` type doesn't accept type parameters, use the \
1796 concrete type's name `{type_name}` instead if you want to \
1797 specify its type parameters"
1798 ),
1799 type_name,
1800 Applicability::MaybeIncorrect,
1801 );
1802 }
1803 }
1804 }
1805 }
1806 _ => {}
1807 }
1808}
1809
1810pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
1811 match assoc_tag {
1812 ty::AssocTag::Fn => "function",
1813 ty::AssocTag::Const => "constant",
1814 ty::AssocTag::Type => "type",
1815 }
1816}