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