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