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