rustc_hir_analysis/hir_ty_lowering/
errors.rs

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, listify, pluralize, struct_span_code_err,
7};
8use rustc_hir as hir;
9use rustc_hir::def::{CtorOf, DefKind, Res};
10use rustc_hir::def_id::DefId;
11use rustc_middle::bug;
12use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
13use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
14use rustc_middle::ty::{
15    self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
16    suggest_constraining_type_param,
17};
18use rustc_session::parse::feature_err;
19use rustc_span::edit_distance::find_best_match_for_name;
20use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
21use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
22use rustc_trait_selection::traits::{
23    FulfillmentError, dyn_compatibility_violations_for_assoc_item,
24};
25use smallvec::SmallVec;
26
27use crate::errors::{
28    self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
29    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
30};
31use crate::fluent_generated as fluent;
32use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
33
34impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
35    /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
36    /// the type parameter's name as a placeholder.
37    pub(crate) fn complain_about_missing_type_params(
38        &self,
39        missing_type_params: Vec<Symbol>,
40        def_id: DefId,
41        span: Span,
42        empty_generic_args: bool,
43    ) {
44        if missing_type_params.is_empty() {
45            return;
46        }
47
48        self.dcx().emit_err(MissingTypeParams {
49            span,
50            def_span: self.tcx().def_span(def_id),
51            span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
52            missing_type_params,
53            empty_generic_args,
54        });
55    }
56
57    /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
58    /// an error and attempt to build a reasonable structured suggestion.
59    pub(crate) fn complain_about_internal_fn_trait(
60        &self,
61        span: Span,
62        trait_def_id: DefId,
63        trait_segment: &'_ hir::PathSegment<'_>,
64        is_impl: bool,
65    ) {
66        if self.tcx().features().unboxed_closures() {
67            return;
68        }
69
70        let trait_def = self.tcx().trait_def(trait_def_id);
71        if !trait_def.paren_sugar {
72            if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar {
73                // For now, require that parenthetical notation be used only with `Fn()` etc.
74                feature_err(
75                    &self.tcx().sess,
76                    sym::unboxed_closures,
77                    span,
78                    "parenthetical notation is only stable when used with `Fn`-family traits",
79                )
80                .emit();
81            }
82
83            return;
84        }
85
86        let sess = self.tcx().sess;
87
88        if trait_segment.args().parenthesized != hir::GenericArgsParentheses::ParenSugar {
89            // For now, require that parenthetical notation be used only with `Fn()` etc.
90            let mut err = feature_err(
91                sess,
92                sym::unboxed_closures,
93                span,
94                "the precise format of `Fn`-family traits' type parameters is subject to change",
95            );
96            // Do not suggest the other syntax if we are in trait impl:
97            // the desugaring would contain an associated type constraint.
98            if !is_impl {
99                err.span_suggestion(
100                    span,
101                    "use parenthetical notation instead",
102                    fn_trait_to_string(self.tcx(), trait_segment, true),
103                    Applicability::MaybeIncorrect,
104                );
105            }
106            err.emit();
107        }
108
109        if is_impl {
110            let trait_name = self.tcx().def_path_str(trait_def_id);
111            self.dcx().emit_err(ManualImplementation { span, trait_name });
112        }
113    }
114
115    pub(super) fn complain_about_assoc_item_not_found<I>(
116        &self,
117        all_candidates: impl Fn() -> I,
118        qself: AssocItemQSelf,
119        assoc_kind: ty::AssocKind,
120        assoc_name: Ident,
121        span: Span,
122        constraint: Option<&hir::AssocItemConstraint<'tcx>>,
123    ) -> ErrorGuaranteed
124    where
125        I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
126    {
127        let tcx = self.tcx();
128
129        // First and foremost, provide a more user-friendly & “intuitive” error on kind mismatches.
130        if let Some(assoc_item) = all_candidates().find_map(|r| {
131            tcx.associated_items(r.def_id())
132                .filter_by_name_unhygienic(assoc_name.name)
133                .find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id()))
134        }) {
135            return self.complain_about_assoc_kind_mismatch(
136                assoc_item, assoc_kind, assoc_name, span, constraint,
137            );
138        }
139
140        let assoc_kind_str = assoc_kind_str(assoc_kind);
141        let qself_str = qself.to_string(tcx);
142
143        // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
144        // valid span, so we point at the whole path segment instead.
145        let is_dummy = assoc_name.span == DUMMY_SP;
146
147        let mut err = errors::AssocItemNotFound {
148            span: if is_dummy { span } else { assoc_name.span },
149            assoc_name,
150            assoc_kind: assoc_kind_str,
151            qself: &qself_str,
152            label: None,
153            sugg: None,
154            // Try to get the span of the identifier within the path's syntax context
155            // (if that's different).
156            within_macro_span: assoc_name.span.within_macro(span, tcx.sess.source_map()),
157        };
158
159        if is_dummy {
160            err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
161            return self.dcx().emit_err(err);
162        }
163
164        let all_candidate_names: Vec<_> = all_candidates()
165            .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
166            .filter_map(|item| {
167                (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
168            })
169            .collect();
170
171        if let Some(suggested_name) =
172            find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
173        {
174            err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
175                span: assoc_name.span,
176                assoc_kind: assoc_kind_str,
177                suggested_name,
178            });
179            return self.dcx().emit_err(err);
180        }
181
182        // If we didn't find a good item in the supertraits (or couldn't get
183        // the supertraits), like in ItemCtxt, then look more generally from
184        // all visible traits. If there's one clear winner, just suggest that.
185
186        let visible_traits: Vec<_> = tcx
187            .visible_traits()
188            .filter(|trait_def_id| {
189                let viz = tcx.visibility(*trait_def_id);
190                let def_id = self.item_def_id();
191                viz.is_accessible_from(def_id, tcx)
192            })
193            .collect();
194
195        let wider_candidate_names: Vec<_> = visible_traits
196            .iter()
197            .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
198            .filter_map(|item| {
199                (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
200            })
201            .collect();
202
203        if let Some(suggested_name) =
204            find_best_match_for_name(&wider_candidate_names, assoc_name.name, None)
205        {
206            if let [best_trait] = visible_traits
207                .iter()
208                .copied()
209                .filter(|trait_def_id| {
210                    tcx.associated_items(trait_def_id)
211                        .filter_by_name_unhygienic(suggested_name)
212                        .any(|item| item.kind == assoc_kind)
213                })
214                .collect::<Vec<_>>()[..]
215            {
216                let trait_name = tcx.def_path_str(best_trait);
217                err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
218                    span: assoc_name.span,
219                    assoc_kind: assoc_kind_str,
220                    trait_name: &trait_name,
221                    suggested_name,
222                    identically_named: suggested_name == assoc_name.name,
223                });
224                if let AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span) = qself
225                    // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're
226                    // inside an opaque type while we're interested in the overarching type alias (TAIT).
227                    // FIXME: However, for trait aliases, this incorrectly returns the enclosing module...
228                    && let item_def_id =
229                        tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
230                    // FIXME: ...which obviously won't have any generics.
231                    && let Some(generics) = tcx.hir_get_generics(item_def_id.def_id)
232                {
233                    // FIXME: Suggest adding supertrait bounds if we have a `Self` type param.
234                    // FIXME(trait_alias): Suggest adding `Self: Trait` to
235                    // `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`.
236                    if generics
237                        .bounds_for_param(ty_param_def_id)
238                        .flat_map(|pred| pred.bounds.iter())
239                        .any(|b| match b {
240                            hir::GenericBound::Trait(t, ..) => {
241                                t.trait_ref.trait_def_id() == Some(best_trait)
242                            }
243                            _ => false,
244                        })
245                    {
246                        // The type param already has a bound for `trait_name`, we just need to
247                        // change the associated item.
248                        err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
249                            span: assoc_name.span,
250                            assoc_kind: assoc_kind_str,
251                            suggested_name,
252                        });
253                        return self.dcx().emit_err(err);
254                    }
255
256                    let trait_args = &ty::GenericArgs::identity_for_item(tcx, best_trait)[1..];
257                    let mut trait_ref = trait_name.clone();
258                    let applicability = if let [arg, args @ ..] = trait_args {
259                        use std::fmt::Write;
260                        write!(trait_ref, "</* {arg}").unwrap();
261                        args.iter().try_for_each(|arg| write!(trait_ref, ", {arg}")).unwrap();
262                        trait_ref += " */>";
263                        Applicability::HasPlaceholders
264                    } else {
265                        Applicability::MaybeIncorrect
266                    };
267
268                    let identically_named = suggested_name == assoc_name.name;
269
270                    if let DefKind::TyAlias = tcx.def_kind(item_def_id)
271                        && !tcx.type_alias_is_lazy(item_def_id)
272                    {
273                        err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTraitQPath {
274                            lo: ty_param_span.shrink_to_lo(),
275                            mi: ty_param_span.shrink_to_hi(),
276                            hi: (!identically_named).then_some(assoc_name.span),
277                            trait_ref,
278                            identically_named,
279                            suggested_name,
280                            applicability,
281                        });
282                    } else {
283                        let mut err = self.dcx().create_err(err);
284                        if suggest_constraining_type_param(
285                            tcx,
286                            generics,
287                            &mut err,
288                            &qself_str,
289                            &trait_ref,
290                            Some(best_trait),
291                            None,
292                        ) && !identically_named
293                        {
294                            // We suggested constraining a type parameter, but the associated item on it
295                            // was also not an exact match, so we also suggest changing it.
296                            err.span_suggestion_verbose(
297                                assoc_name.span,
298                                fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
299                                suggested_name,
300                                Applicability::MaybeIncorrect,
301                            );
302                        }
303                        return err.emit();
304                    }
305                }
306                return self.dcx().emit_err(err);
307            }
308        }
309
310        // If we still couldn't find any associated item, and only one associated item exists,
311        // suggest using it.
312        if let [candidate_name] = all_candidate_names.as_slice() {
313            err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
314                span: assoc_name.span,
315                qself: &qself_str,
316                assoc_kind: assoc_kind_str,
317                suggested_name: *candidate_name,
318            });
319        } else {
320            err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
321        }
322
323        self.dcx().emit_err(err)
324    }
325
326    fn complain_about_assoc_kind_mismatch(
327        &self,
328        assoc_item: &ty::AssocItem,
329        assoc_kind: ty::AssocKind,
330        ident: Ident,
331        span: Span,
332        constraint: Option<&hir::AssocItemConstraint<'tcx>>,
333    ) -> ErrorGuaranteed {
334        let tcx = self.tcx();
335
336        let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
337            && let Some(constraint) = constraint
338            && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
339        {
340            let lo = if constraint.gen_args.span_ext.is_dummy() {
341                ident.span
342            } else {
343                constraint.gen_args.span_ext
344            };
345            Some(lo.between(span.shrink_to_hi()))
346        } else {
347            None
348        };
349
350        // FIXME(associated_const_equality): This has quite a few false positives and negatives.
351        let wrap_in_braces_sugg = if let Some(constraint) = constraint
352            && let Some(hir_ty) = constraint.ty()
353            && let ty = self.lower_ty(hir_ty)
354            && (ty.is_enum() || ty.references_error())
355            && tcx.features().associated_const_equality()
356        {
357            Some(errors::AssocKindMismatchWrapInBracesSugg {
358                lo: hir_ty.span.shrink_to_lo(),
359                hi: hir_ty.span.shrink_to_hi(),
360            })
361        } else {
362            None
363        };
364
365        // For equality constraints, we want to blame the term (RHS) instead of the item (LHS) since
366        // one can argue that that's more “intuitive” to the user.
367        let (span, expected_because_label, expected, got) = if let Some(constraint) = constraint
368            && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
369        {
370            let span = match term {
371                hir::Term::Ty(ty) => ty.span,
372                hir::Term::Const(ct) => ct.span(),
373            };
374            (span, Some(ident.span), assoc_item.kind, assoc_kind)
375        } else {
376            (ident.span, None, assoc_kind, assoc_item.kind)
377        };
378
379        self.dcx().emit_err(errors::AssocKindMismatch {
380            span,
381            expected: assoc_kind_str(expected),
382            got: assoc_kind_str(got),
383            expected_because_label,
384            assoc_kind: assoc_kind_str(assoc_item.kind),
385            def_span: tcx.def_span(assoc_item.def_id),
386            bound_on_assoc_const_label,
387            wrap_in_braces_sugg,
388        })
389    }
390
391    pub(super) fn report_ambiguous_assoc(
392        &self,
393        span: Span,
394        types: &[String],
395        traits: &[String],
396        name: Symbol,
397        kind: ty::AssocKind,
398    ) -> ErrorGuaranteed {
399        let kind_str = assoc_kind_str(kind);
400        let mut err =
401            struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
402        if self
403            .tcx()
404            .resolutions(())
405            .confused_type_with_std_module
406            .keys()
407            .any(|full_span| full_span.contains(span))
408        {
409            err.span_suggestion_verbose(
410                span.shrink_to_lo(),
411                "you are looking for the module in `std`, not the primitive type",
412                "std::",
413                Applicability::MachineApplicable,
414            );
415        } else {
416            let mut types = types.to_vec();
417            types.sort();
418            let mut traits = traits.to_vec();
419            traits.sort();
420            match (&types[..], &traits[..]) {
421                ([], []) => {
422                    err.span_suggestion_verbose(
423                        span,
424                        format!(
425                            "if there were a type named `Type` that implements a trait named \
426                             `Trait` with associated {kind_str} `{name}`, you could use the \
427                             fully-qualified path",
428                        ),
429                        format!("<Type as Trait>::{name}"),
430                        Applicability::HasPlaceholders,
431                    );
432                }
433                ([], [trait_str]) => {
434                    err.span_suggestion_verbose(
435                        span,
436                        format!(
437                            "if there were a type named `Example` that implemented `{trait_str}`, \
438                             you could use the fully-qualified path",
439                        ),
440                        format!("<Example as {trait_str}>::{name}"),
441                        Applicability::HasPlaceholders,
442                    );
443                }
444                ([], traits) => {
445                    err.span_suggestions(
446                        span,
447                        format!(
448                            "if there were a type named `Example` that implemented one of the \
449                             traits with associated {kind_str} `{name}`, you could use the \
450                             fully-qualified path",
451                        ),
452                        traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
453                        Applicability::HasPlaceholders,
454                    );
455                }
456                ([type_str], []) => {
457                    err.span_suggestion_verbose(
458                        span,
459                        format!(
460                            "if there were a trait named `Example` with associated {kind_str} `{name}` \
461                             implemented for `{type_str}`, you could use the fully-qualified path",
462                        ),
463                        format!("<{type_str} as Example>::{name}"),
464                        Applicability::HasPlaceholders,
465                    );
466                }
467                (types, []) => {
468                    err.span_suggestions(
469                        span,
470                        format!(
471                            "if there were a trait named `Example` with associated {kind_str} `{name}` \
472                             implemented for one of the types, you could use the fully-qualified \
473                             path",
474                        ),
475                        types
476                            .into_iter()
477                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
478                        Applicability::HasPlaceholders,
479                    );
480                }
481                (types, traits) => {
482                    let mut suggestions = vec![];
483                    for type_str in types {
484                        for trait_str in traits {
485                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
486                        }
487                    }
488                    err.span_suggestions(
489                        span,
490                        "use fully-qualified syntax",
491                        suggestions,
492                        Applicability::MachineApplicable,
493                    );
494                }
495            }
496        }
497        err.emit()
498    }
499
500    pub(crate) fn complain_about_ambiguous_inherent_assoc(
501        &self,
502        name: Ident,
503        candidates: Vec<DefId>,
504        span: Span,
505    ) -> ErrorGuaranteed {
506        let mut err = struct_span_code_err!(
507            self.dcx(),
508            name.span,
509            E0034,
510            "multiple applicable items in scope"
511        );
512        err.span_label(name.span, format!("multiple `{name}` found"));
513        self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
514        err.emit()
515    }
516
517    // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
518    fn note_ambiguous_inherent_assoc_ty(
519        &self,
520        err: &mut Diag<'_>,
521        candidates: Vec<DefId>,
522        span: Span,
523    ) {
524        let tcx = self.tcx();
525
526        // Dynamic limit to avoid hiding just one candidate, which is silly.
527        let limit = if candidates.len() == 5 { 5 } else { 4 };
528
529        for (index, &item) in candidates.iter().take(limit).enumerate() {
530            let impl_ = tcx.impl_of_method(item).unwrap();
531
532            let note_span = if item.is_local() {
533                Some(tcx.def_span(item))
534            } else if impl_.is_local() {
535                Some(tcx.def_span(impl_))
536            } else {
537                None
538            };
539
540            let title = if candidates.len() > 1 {
541                format!("candidate #{}", index + 1)
542            } else {
543                "the candidate".into()
544            };
545
546            let impl_ty = tcx.at(span).type_of(impl_).instantiate_identity();
547            let note = format!("{title} is defined in an impl for the type `{impl_ty}`");
548
549            if let Some(span) = note_span {
550                err.span_note(span, note);
551            } else {
552                err.note(note);
553            }
554        }
555        if candidates.len() > limit {
556            err.note(format!("and {} others", candidates.len() - limit));
557        }
558    }
559
560    // FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
561    pub(crate) fn complain_about_inherent_assoc_not_found(
562        &self,
563        name: Ident,
564        self_ty: Ty<'tcx>,
565        candidates: Vec<(DefId, (DefId, DefId))>,
566        fulfillment_errors: Vec<FulfillmentError<'tcx>>,
567        span: Span,
568        kind: ty::AssocKind,
569    ) -> ErrorGuaranteed {
570        // FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
571        // Either
572        // * update this code by applying changes similar to #106702 or by taking a
573        //   Vec<(DefId, (DefId, DefId), Option<Vec<FulfillmentError<'tcx>>>)> or
574        // * deduplicate this code across the two crates.
575
576        let tcx = self.tcx();
577
578        let kind_str = assoc_kind_str(kind);
579        let adt_did = self_ty.ty_adt_def().map(|def| def.did());
580        let add_def_label = |err: &mut Diag<'_>| {
581            if let Some(did) = adt_did {
582                err.span_label(
583                    tcx.def_span(did),
584                    format!(
585                        "associated {kind_str} `{name}` not found for this {}",
586                        tcx.def_descr(did)
587                    ),
588                );
589            }
590        };
591
592        if fulfillment_errors.is_empty() {
593            // FIXME(fmease): Copied from `rustc_hir_typeck::method::probe`. Deduplicate.
594
595            let limit = if candidates.len() == 5 { 5 } else { 4 };
596            let type_candidates = candidates
597                .iter()
598                .take(limit)
599                .map(|&(impl_, _)| {
600                    format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity())
601                })
602                .collect::<Vec<_>>()
603                .join("\n");
604            let additional_types = if candidates.len() > limit {
605                format!("\nand {} more types", candidates.len() - limit)
606            } else {
607                String::new()
608            };
609
610            let mut err = struct_span_code_err!(
611                self.dcx(),
612                name.span,
613                E0220,
614                "associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
615            );
616            err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
617            err.note(format!(
618                "the associated {kind_str} was found for\n{type_candidates}{additional_types}",
619            ));
620            add_def_label(&mut err);
621            return err.emit();
622        }
623
624        let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
625
626        let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
627            let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
628            match self_ty.kind() {
629                // Point at the type that couldn't satisfy the bound.
630                ty::Adt(def, _) => {
631                    bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
632                }
633                // Point at the trait object that couldn't satisfy the bound.
634                ty::Dynamic(preds, _, _) => {
635                    for pred in preds.iter() {
636                        match pred.skip_binder() {
637                            ty::ExistentialPredicate::Trait(tr) => {
638                                bound_spans
639                                    .get_mut_or_insert_default(tcx.def_span(tr.def_id))
640                                    .push(msg.clone());
641                            }
642                            ty::ExistentialPredicate::Projection(_)
643                            | ty::ExistentialPredicate::AutoTrait(_) => {}
644                        }
645                    }
646                }
647                // Point at the closure that couldn't satisfy the bound.
648                ty::Closure(def_id, _) => {
649                    bound_spans
650                        .get_mut_or_insert_default(tcx.def_span(*def_id))
651                        .push(format!("`{quiet}`"));
652                }
653                _ => {}
654            }
655        };
656
657        let format_pred = |pred: ty::Predicate<'tcx>| {
658            let bound_predicate = pred.kind();
659            match bound_predicate.skip_binder() {
660                ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
661                    // `<Foo as Iterator>::Item = String`.
662                    let projection_term = pred.projection_term;
663                    let quiet_projection_term =
664                        projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
665
666                    let term = pred.term;
667                    let obligation = format!("{projection_term} = {term}");
668                    let quiet = format!("{quiet_projection_term} = {term}");
669
670                    bound_span_label(projection_term.self_ty(), &obligation, &quiet);
671                    Some((obligation, projection_term.self_ty()))
672                }
673                ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
674                    let p = poly_trait_ref.trait_ref;
675                    let self_ty = p.self_ty();
676                    let path = p.print_only_trait_path();
677                    let obligation = format!("{self_ty}: {path}");
678                    let quiet = format!("_: {path}");
679                    bound_span_label(self_ty, &obligation, &quiet);
680                    Some((obligation, self_ty))
681                }
682                _ => None,
683            }
684        };
685
686        // FIXME(fmease): `rustc_hir_typeck::method::suggest` uses a `skip_list` to filter out some bounds.
687        // I would do the same here if it didn't mean more code duplication.
688        let mut bounds: Vec<_> = fulfillment_errors
689            .into_iter()
690            .map(|error| error.root_obligation.predicate)
691            .filter_map(format_pred)
692            .map(|(p, _)| format!("`{p}`"))
693            .collect();
694        bounds.sort();
695        bounds.dedup();
696
697        let mut err = self.dcx().struct_span_err(
698            name.span,
699            format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
700        );
701        if !bounds.is_empty() {
702            err.note(format!(
703                "the following trait bounds were not satisfied:\n{}",
704                bounds.join("\n")
705            ));
706        }
707        err.span_label(
708            name.span,
709            format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
710        );
711
712        for (span, mut bounds) in bound_spans {
713            if !tcx.sess.source_map().is_span_accessible(span) {
714                continue;
715            }
716            bounds.sort();
717            bounds.dedup();
718            let msg = match &bounds[..] {
719                [bound] => format!("doesn't satisfy {bound}"),
720                bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()),
721                [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")),
722                [] => unreachable!(),
723            };
724            err.span_label(span, msg);
725        }
726        add_def_label(&mut err);
727        err.emit()
728    }
729
730    /// When there are any missing associated types, emit an E0191 error and attempt to supply a
731    /// reasonable suggestion on how to write it. For the case of multiple associated types in the
732    /// same trait bound have the same name (as they come from different supertraits), we instead
733    /// emit a generic note suggesting using a `where` clause to constraint instead.
734    pub(crate) fn check_for_required_assoc_tys(
735        &self,
736        spans: SmallVec<[Span; 1]>,
737        missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
738        potential_assoc_types: Vec<usize>,
739        trait_bounds: &[hir::PolyTraitRef<'_>],
740    ) -> Result<(), ErrorGuaranteed> {
741        if missing_assoc_types.is_empty() {
742            return Ok(());
743        }
744
745        let principal_span = *spans.first().unwrap();
746
747        let tcx = self.tcx();
748        // FIXME: This logic needs some more care w.r.t handling of conflicts
749        let missing_assoc_types: Vec<_> = missing_assoc_types
750            .into_iter()
751            .map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
752            .collect();
753        let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
754        let mut names_len = 0;
755
756        // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
757        // `issue-22560.rs`.
758        let mut dyn_compatibility_violations = Ok(());
759        for (assoc_item, trait_ref) in &missing_assoc_types {
760            names.entry(trait_ref).or_default().push(assoc_item.name);
761            names_len += 1;
762
763            let violations =
764                dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
765            if !violations.is_empty() {
766                dyn_compatibility_violations = Err(report_dyn_incompatibility(
767                    tcx,
768                    principal_span,
769                    None,
770                    trait_ref.def_id(),
771                    &violations,
772                )
773                .emit());
774            }
775        }
776
777        if let Err(guar) = dyn_compatibility_violations {
778            return Err(guar);
779        }
780
781        // related to issue #91997, turbofishes added only when in an expr or pat
782        let mut in_expr_or_pat = false;
783        if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
784            let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
785            in_expr_or_pat = match grandparent {
786                hir::Node::Expr(_) | hir::Node::Pat(_) => true,
787                _ => false,
788            };
789        }
790
791        // We get all the associated items that _are_ set,
792        // so that we can check if any of their names match one of the ones we are missing.
793        // This would mean that they are shadowing the associated type we are missing,
794        // and we can then use their span to indicate this to the user.
795        let bound_names = trait_bounds
796            .iter()
797            .filter_map(|poly_trait_ref| {
798                let path = poly_trait_ref.trait_ref.path.segments.last()?;
799                let args = path.args?;
800
801                Some(args.constraints.iter().filter_map(|constraint| {
802                    let ident = constraint.ident;
803
804                    let Res::Def(DefKind::Trait, trait_def) = path.res else {
805                        return None;
806                    };
807
808                    let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
809                        tcx,
810                        ident,
811                        ty::AssocKind::Type,
812                        trait_def,
813                    );
814
815                    Some((ident.name, assoc_item?))
816                }))
817            })
818            .flatten()
819            .collect::<UnordMap<Symbol, &ty::AssocItem>>();
820
821        let mut names = names
822            .into_iter()
823            .map(|(trait_, mut assocs)| {
824                assocs.sort();
825                let trait_ = trait_.print_trait_sugared();
826                format!(
827                    "{} in `{trait_}`",
828                    listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
829                )
830            })
831            .collect::<Vec<String>>();
832        names.sort();
833        let names = names.join(", ");
834
835        let mut err = struct_span_code_err!(
836            self.dcx(),
837            principal_span,
838            E0191,
839            "the value of the associated type{} {} must be specified",
840            pluralize!(names_len),
841            names,
842        );
843        let mut suggestions = vec![];
844        let mut types_count = 0;
845        let mut where_constraints = vec![];
846        let mut already_has_generics_args_suggestion = false;
847
848        let mut names: UnordMap<_, usize> = Default::default();
849        for (item, _) in &missing_assoc_types {
850            types_count += 1;
851            *names.entry(item.name).or_insert(0) += 1;
852        }
853        let mut dupes = false;
854        let mut shadows = false;
855        for (item, trait_ref) in &missing_assoc_types {
856            let prefix = if names[&item.name] > 1 {
857                let trait_def_id = trait_ref.def_id();
858                dupes = true;
859                format!("{}::", tcx.def_path_str(trait_def_id))
860            } else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
861                let trait_def_id = trait_ref.def_id();
862                shadows = true;
863                format!("{}::", tcx.def_path_str(trait_def_id))
864            } else {
865                String::new()
866            };
867
868            let mut is_shadowed = false;
869
870            if let Some(assoc_item) = bound_names.get(&item.name)
871                && *assoc_item != item
872            {
873                is_shadowed = true;
874
875                let rename_message =
876                    if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
877                err.span_label(
878                    tcx.def_span(assoc_item.def_id),
879                    format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
880                );
881            }
882
883            let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
884
885            if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
886                err.span_label(
887                    sp,
888                    format!("`{}{}` defined here{}", prefix, item.name, rename_message),
889                );
890            }
891        }
892        if potential_assoc_types.len() == missing_assoc_types.len() {
893            // When the amount of missing associated types equals the number of
894            // extra type arguments present. A suggesting to replace the generic args with
895            // associated types is already emitted.
896            already_has_generics_args_suggestion = true;
897        } else if let (Ok(snippet), false, false) =
898            (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
899        {
900            let types: Vec<_> = missing_assoc_types
901                .iter()
902                .map(|(item, _)| format!("{} = Type", item.name))
903                .collect();
904            let code = if let Some(snippet) = snippet.strip_suffix('>') {
905                // The user wrote `Trait<'a>` or similar and we don't have a type we can
906                // suggest, but at least we can clue them to the correct syntax
907                // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
908                // suggestion.
909                format!("{}, {}>", snippet, types.join(", "))
910            } else if in_expr_or_pat {
911                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
912                // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
913                format!("{}::<{}>", snippet, types.join(", "))
914            } else {
915                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
916                // least we can clue them to the correct syntax `Iterator<Item = Type>`.
917                format!("{}<{}>", snippet, types.join(", "))
918            };
919            suggestions.push((principal_span, code));
920        } else if dupes {
921            where_constraints.push(principal_span);
922        }
923
924        let where_msg = "consider introducing a new type parameter, adding `where` constraints \
925                         using the fully-qualified path to the associated types";
926        if !where_constraints.is_empty() && suggestions.is_empty() {
927            // If there are duplicates associated type names and a single trait bound do not
928            // use structured suggestion, it means that there are multiple supertraits with
929            // the same associated type name.
930            err.help(where_msg);
931        }
932        if suggestions.len() != 1 || already_has_generics_args_suggestion {
933            // We don't need this label if there's an inline suggestion, show otherwise.
934            let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
935            for (item, _) in &missing_assoc_types {
936                types_count += 1;
937                *names.entry(item.name).or_insert(0) += 1;
938            }
939            let mut label = vec![];
940            for (item, trait_ref) in &missing_assoc_types {
941                let postfix = if names[&item.name] > 1 {
942                    format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
943                } else {
944                    String::new()
945                };
946                label.push(format!("`{}`{}", item.name, postfix));
947            }
948            if !label.is_empty() {
949                err.span_label(
950                    principal_span,
951                    format!(
952                        "associated type{} {} must be specified",
953                        pluralize!(label.len()),
954                        label.join(", "),
955                    ),
956                );
957            }
958        }
959        suggestions.sort_by_key(|&(span, _)| span);
960        // There are cases where one bound points to a span within another bound's span, like when
961        // you have code like the following (#115019), so we skip providing a suggestion in those
962        // cases to avoid having a malformed suggestion.
963        //
964        // pub struct Flatten<I> {
965        //     inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>::core,
966        //             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
967        //             |                  ^^^^^^^^^^^^^^^^^^^^^
968        //             |                  |
969        //             |                  associated types `Item`, `IntoIter` must be specified
970        //             associated types `Item`, `IntoIter` must be specified
971        // }
972        let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
973        if !suggestions.is_empty() && !overlaps {
974            err.multipart_suggestion(
975                format!("specify the associated type{}", pluralize!(types_count)),
976                suggestions,
977                Applicability::HasPlaceholders,
978            );
979            if !where_constraints.is_empty() {
980                err.span_help(where_constraints, where_msg);
981            }
982        }
983
984        Err(err.emit())
985    }
986
987    /// On ambiguous associated type, look for an associated function whose name matches the
988    /// extended path and, if found, emit an E0223 error with a structured suggestion.
989    /// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195)
990    pub(crate) fn maybe_report_similar_assoc_fn(
991        &self,
992        span: Span,
993        qself_ty: Ty<'tcx>,
994        qself: &hir::Ty<'_>,
995    ) -> Result<(), ErrorGuaranteed> {
996        let tcx = self.tcx();
997        if let Some((_, node)) = tcx.hir_parent_iter(qself.hir_id).skip(1).next()
998            && let hir::Node::Expr(hir::Expr {
999                kind:
1000                    hir::ExprKind::Path(hir::QPath::TypeRelative(
1001                        hir::Ty {
1002                            kind:
1003                                hir::TyKind::Path(hir::QPath::TypeRelative(
1004                                    _,
1005                                    hir::PathSegment { ident: ident2, .. },
1006                                )),
1007                            ..
1008                        },
1009                        hir::PathSegment { ident: ident3, .. },
1010                    )),
1011                ..
1012            }) = node
1013            && let Some(inherent_impls) = qself_ty
1014                .ty_adt_def()
1015                .map(|adt_def| tcx.inherent_impls(adt_def.did()))
1016                .or_else(|| {
1017                    simplify_type(tcx, qself_ty, TreatParams::InstantiateWithInfer)
1018                        .map(|simple_ty| tcx.incoherent_impls(simple_ty))
1019                })
1020            && let name = Symbol::intern(&format!("{ident2}_{ident3}"))
1021            && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
1022                .iter()
1023                .flat_map(|inherent_impl| {
1024                    tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
1025                })
1026                .next()
1027        {
1028            Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
1029                .with_span_suggestion_verbose(
1030                    ident2.span.to(ident3.span),
1031                    format!("there is an associated function with a similar name: `{name}`"),
1032                    name,
1033                    Applicability::MaybeIncorrect,
1034                )
1035                .emit())
1036        } else {
1037            Ok(())
1038        }
1039    }
1040
1041    pub fn report_prohibit_generics_error<'a>(
1042        &self,
1043        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1044        args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
1045        err_extend: GenericsArgsErrExtend<'a>,
1046    ) -> ErrorGuaranteed {
1047        #[derive(PartialEq, Eq, Hash)]
1048        enum ProhibitGenericsArg {
1049            Lifetime,
1050            Type,
1051            Const,
1052            Infer,
1053        }
1054
1055        let mut prohibit_args = FxIndexSet::default();
1056        args_visitors.for_each(|arg| {
1057            match arg {
1058                hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
1059                hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
1060                hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
1061                hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
1062            };
1063        });
1064
1065        let segments: Vec<_> = segments.collect();
1066        let types_and_spans: Vec<_> = segments
1067            .iter()
1068            .flat_map(|segment| {
1069                if segment.args().args.is_empty() {
1070                    None
1071                } else {
1072                    Some((
1073                        match segment.res {
1074                            Res::PrimTy(ty) => {
1075                                format!("{} `{}`", segment.res.descr(), ty.name())
1076                            }
1077                            Res::Def(_, def_id)
1078                                if let Some(name) = self.tcx().opt_item_name(def_id) =>
1079                            {
1080                                format!("{} `{name}`", segment.res.descr())
1081                            }
1082                            Res::Err => "this type".to_string(),
1083                            _ => segment.res.descr().to_string(),
1084                        },
1085                        segment.ident.span,
1086                    ))
1087                }
1088            })
1089            .collect();
1090        let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
1091            .expect("expected one segment to deny");
1092
1093        let arg_spans: Vec<Span> =
1094            segments.iter().flat_map(|segment| segment.args().args).map(|arg| arg.span()).collect();
1095
1096        let mut kinds = Vec::with_capacity(4);
1097        prohibit_args.iter().for_each(|arg| match arg {
1098            ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
1099            ProhibitGenericsArg::Type => kinds.push("type"),
1100            ProhibitGenericsArg::Const => kinds.push("const"),
1101            ProhibitGenericsArg::Infer => kinds.push("generic"),
1102        });
1103
1104        let s = pluralize!(kinds.len());
1105        let kind =
1106            listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit");
1107        let last_span = *arg_spans.last().unwrap();
1108        let span: MultiSpan = arg_spans.into();
1109        let mut err = struct_span_code_err!(
1110            self.dcx(),
1111            span,
1112            E0109,
1113            "{kind} arguments are not allowed on {this_type}",
1114        );
1115        err.span_label(last_span, format!("{kind} argument{s} not allowed"));
1116        for (what, span) in types_and_spans {
1117            err.span_label(span, format!("not allowed on {what}"));
1118        }
1119        generics_args_err_extend(self.tcx(), segments.into_iter(), &mut err, err_extend);
1120        err.emit()
1121    }
1122
1123    pub fn report_trait_object_addition_traits_error(
1124        &self,
1125        regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
1126    ) -> ErrorGuaranteed {
1127        // we use the last span to point at the traits themselves,
1128        // and all other preceding spans are trait alias expansions.
1129        let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap();
1130        let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap();
1131        let mut err = struct_span_code_err!(
1132            self.dcx(),
1133            *regular_traits[1].1.first().unwrap(),
1134            E0225,
1135            "only auto traits can be used as additional traits in a trait object"
1136        );
1137        err.span_label(first_span, "first non-auto trait");
1138        for &alias_span in first_alias_spans {
1139            err.span_label(alias_span, "first non-auto trait comes from this alias");
1140        }
1141        err.span_label(second_span, "additional non-auto trait");
1142        for &alias_span in second_alias_spans {
1143            err.span_label(alias_span, "second non-auto trait comes from this alias");
1144        }
1145        err.help(format!(
1146            "consider creating a new trait with all of these as supertraits and using that \
1147             trait here instead: `trait NewTrait: {} {{}}`",
1148            regular_traits
1149                .iter()
1150                // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
1151                .map(|(pred, _)| pred
1152                    .map_bound(|pred| pred.trait_ref)
1153                    .print_only_trait_path()
1154                    .to_string())
1155                .collect::<Vec<_>>()
1156                .join(" + "),
1157        ));
1158        err.note(
1159            "auto-traits like `Send` and `Sync` are traits that have special properties; \
1160             for more information on them, visit \
1161             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
1162        );
1163        err.emit()
1164    }
1165
1166    pub fn report_trait_object_with_no_traits_error(
1167        &self,
1168        span: Span,
1169        user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
1170    ) -> ErrorGuaranteed {
1171        let tcx = self.tcx();
1172        let trait_alias_span = user_written_clauses
1173            .into_iter()
1174            .filter_map(|(clause, _)| clause.as_trait_clause())
1175            .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id()))
1176            .map(|trait_ref| tcx.def_span(trait_ref.def_id()));
1177
1178        self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
1179    }
1180}
1181
1182/// Emit an error for the given associated item constraint.
1183pub fn prohibit_assoc_item_constraint(
1184    cx: &dyn HirTyLowerer<'_>,
1185    constraint: &hir::AssocItemConstraint<'_>,
1186    segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
1187) -> ErrorGuaranteed {
1188    let tcx = cx.tcx();
1189    let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
1190        span: constraint.span,
1191        fn_trait_expansion: if let Some((_, segment, span)) = segment
1192            && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
1193        {
1194            Some(ParenthesizedFnTraitExpansion {
1195                span,
1196                expanded_type: fn_trait_to_string(tcx, segment, false),
1197            })
1198        } else {
1199            None
1200        },
1201    });
1202
1203    // Emit a suggestion to turn the assoc item binding into a generic arg
1204    // if the relevant item has a generic param whose name matches the binding name;
1205    // otherwise suggest the removal of the binding.
1206    if let Some((def_id, segment, _)) = segment
1207        && segment.args().parenthesized == hir::GenericArgsParentheses::No
1208    {
1209        // Suggests removal of the offending binding
1210        let suggest_removal = |e: &mut Diag<'_>| {
1211            let constraints = segment.args().constraints;
1212            let args = segment.args().args;
1213
1214            // Compute the span to remove based on the position
1215            // of the binding. We do that as follows:
1216            //  1. Find the index of the binding in the list of bindings
1217            //  2. Locate the spans preceding and following the binding.
1218            //     If it's the first binding the preceding span would be
1219            //     that of the last arg
1220            //  3. Using this information work out whether the span
1221            //     to remove will start from the end of the preceding span,
1222            //     the start of the next span or will simply be the
1223            //     span encomassing everything within the generics brackets
1224
1225            let Some(index) = constraints.iter().position(|b| b.hir_id == constraint.hir_id) else {
1226                bug!("a type binding exists but its HIR ID not found in generics");
1227            };
1228
1229            let preceding_span = if index > 0 {
1230                Some(constraints[index - 1].span)
1231            } else {
1232                args.last().map(|a| a.span())
1233            };
1234
1235            let next_span = constraints.get(index + 1).map(|constraint| constraint.span);
1236
1237            let removal_span = match (preceding_span, next_span) {
1238                (Some(prec), _) => constraint.span.with_lo(prec.hi()),
1239                (None, Some(next)) => constraint.span.with_hi(next.lo()),
1240                (None, None) => {
1241                    let Some(generics_span) = segment.args().span_ext() else {
1242                        bug!("a type binding exists but generic span is empty");
1243                    };
1244
1245                    generics_span
1246                }
1247            };
1248
1249            // Now emit the suggestion
1250            e.span_suggestion_verbose(
1251                removal_span,
1252                format!("consider removing this associated item {}", constraint.kind.descr()),
1253                "",
1254                Applicability::MaybeIncorrect,
1255            );
1256        };
1257
1258        // Suggest replacing the associated item binding with a generic argument.
1259        // i.e., replacing `<..., T = A, ...>` with `<..., A, ...>`.
1260        let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
1261            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
1262                e.span_suggestion_verbose(
1263                    constraint.span,
1264                    format!("to use `{snippet}` as a generic argument specify it directly"),
1265                    snippet,
1266                    Applicability::MaybeIncorrect,
1267                );
1268            }
1269        };
1270
1271        // Check if the type has a generic param with the same name
1272        // as the assoc type name in the associated item binding.
1273        let generics = tcx.generics_of(def_id);
1274        let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name);
1275
1276        // Now emit the appropriate suggestion
1277        if let Some(matching_param) = matching_param {
1278            match (constraint.kind, &matching_param.kind) {
1279                (
1280                    hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) },
1281                    GenericParamDefKind::Type { .. },
1282                ) => suggest_direct_use(&mut err, ty.span),
1283                (
1284                    hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
1285                    GenericParamDefKind::Const { .. },
1286                ) => {
1287                    suggest_direct_use(&mut err, c.span());
1288                }
1289                (hir::AssocItemConstraintKind::Bound { bounds }, _) => {
1290                    // Suggest `impl<T: Bound> Trait<T> for Foo` when finding
1291                    // `impl Trait<T: Bound> for Foo`
1292
1293                    // Get the parent impl block based on the binding we have
1294                    // and the trait DefId
1295                    let impl_block = tcx
1296                        .hir_parent_iter(constraint.hir_id)
1297                        .find_map(|(_, node)| node.impl_block_of_trait(def_id));
1298
1299                    let type_with_constraints =
1300                        tcx.sess.source_map().span_to_snippet(constraint.span);
1301
1302                    if let Some(impl_block) = impl_block
1303                        && let Ok(type_with_constraints) = type_with_constraints
1304                    {
1305                        // Filter out the lifetime parameters because
1306                        // they should be declared before the type parameter
1307                        let lifetimes: String = bounds
1308                            .iter()
1309                            .filter_map(|bound| {
1310                                if let hir::GenericBound::Outlives(lifetime) = bound {
1311                                    Some(format!("{lifetime}, "))
1312                                } else {
1313                                    None
1314                                }
1315                            })
1316                            .collect();
1317                        // Figure out a span and suggestion string based on
1318                        // whether there are any existing parameters
1319                        let param_decl = if let Some(param_span) =
1320                            impl_block.generics.span_for_param_suggestion()
1321                        {
1322                            (param_span, format!(", {lifetimes}{type_with_constraints}"))
1323                        } else {
1324                            (
1325                                impl_block.generics.span.shrink_to_lo(),
1326                                format!("<{lifetimes}{type_with_constraints}>"),
1327                            )
1328                        };
1329                        let suggestions = vec![
1330                            param_decl,
1331                            (constraint.span.with_lo(constraint.ident.span.hi()), String::new()),
1332                        ];
1333
1334                        err.multipart_suggestion_verbose(
1335                            "declare the type parameter right after the `impl` keyword",
1336                            suggestions,
1337                            Applicability::MaybeIncorrect,
1338                        );
1339                    }
1340                }
1341                _ => suggest_removal(&mut err),
1342            }
1343        } else {
1344            suggest_removal(&mut err);
1345        }
1346    }
1347
1348    err.emit()
1349}
1350
1351pub(crate) fn fn_trait_to_string(
1352    tcx: TyCtxt<'_>,
1353    trait_segment: &hir::PathSegment<'_>,
1354    parenthesized: bool,
1355) -> String {
1356    let args = trait_segment
1357        .args
1358        .and_then(|args| args.args.first())
1359        .and_then(|arg| match arg {
1360            hir::GenericArg::Type(ty) => match ty.kind {
1361                hir::TyKind::Tup(t) => t
1362                    .iter()
1363                    .map(|e| tcx.sess.source_map().span_to_snippet(e.span))
1364                    .collect::<Result<Vec<_>, _>>()
1365                    .map(|a| a.join(", ")),
1366                _ => tcx.sess.source_map().span_to_snippet(ty.span),
1367            }
1368            .map(|s| {
1369                // `is_empty()` checks to see if the type is the unit tuple, if so we don't want a comma
1370                if parenthesized || s.is_empty() { format!("({s})") } else { format!("({s},)") }
1371            })
1372            .ok(),
1373            _ => None,
1374        })
1375        .unwrap_or_else(|| "()".to_string());
1376
1377    let ret = trait_segment
1378        .args()
1379        .constraints
1380        .iter()
1381        .find_map(|c| {
1382            if c.ident.name == sym::Output
1383                && let Some(ty) = c.ty()
1384                && ty.span != tcx.hir().span(trait_segment.hir_id)
1385            {
1386                tcx.sess.source_map().span_to_snippet(ty.span).ok()
1387            } else {
1388                None
1389            }
1390        })
1391        .unwrap_or_else(|| "()".to_string());
1392
1393    if parenthesized {
1394        format!("{}{} -> {}", trait_segment.ident, args, ret)
1395    } else {
1396        format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
1397    }
1398}
1399
1400/// Used for generics args error extend.
1401pub enum GenericsArgsErrExtend<'tcx> {
1402    EnumVariant {
1403        qself: &'tcx hir::Ty<'tcx>,
1404        assoc_segment: &'tcx hir::PathSegment<'tcx>,
1405        adt_def: AdtDef<'tcx>,
1406    },
1407    OpaqueTy,
1408    PrimTy(hir::PrimTy),
1409    SelfTyAlias {
1410        def_id: DefId,
1411        span: Span,
1412    },
1413    SelfTyParam(Span),
1414    Param(DefId),
1415    DefVariant(&'tcx [hir::PathSegment<'tcx>]),
1416    None,
1417}
1418
1419fn generics_args_err_extend<'a>(
1420    tcx: TyCtxt<'_>,
1421    segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1422    err: &mut Diag<'_>,
1423    err_extend: GenericsArgsErrExtend<'a>,
1424) {
1425    match err_extend {
1426        GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
1427            err.note("enum variants can't have type parameters");
1428            let type_name = tcx.item_name(adt_def.did());
1429            let msg = format!(
1430                "you might have meant to specify type parameters on enum \
1431                `{type_name}`"
1432            );
1433            let Some(args) = assoc_segment.args else {
1434                return;
1435            };
1436            // Get the span of the generics args *including* the leading `::`.
1437            // We do so by stretching args.span_ext to the left by 2. Earlier
1438            // it was done based on the end of assoc segment but that sometimes
1439            // led to impossible spans and caused issues like #116473
1440            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
1441            if tcx.generics_of(adt_def.did()).is_empty() {
1442                // FIXME(estebank): we could also verify that the arguments being
1443                // work for the `enum`, instead of just looking if it takes *any*.
1444                err.span_suggestion_verbose(
1445                    args_span,
1446                    format!("{type_name} doesn't have generic parameters"),
1447                    "",
1448                    Applicability::MachineApplicable,
1449                );
1450                return;
1451            }
1452            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
1453                err.note(msg);
1454                return;
1455            };
1456            let (qself_sugg_span, is_self) =
1457                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1458                    // If the path segment already has type params, we want to overwrite
1459                    // them.
1460                    match &path.segments {
1461                        // `segment` is the previous to last element on the path,
1462                        // which would normally be the `enum` itself, while the last
1463                        // `_` `PathSegment` corresponds to the variant.
1464                        [
1465                            ..,
1466                            hir::PathSegment {
1467                                ident, args, res: Res::Def(DefKind::Enum, _), ..
1468                            },
1469                            _,
1470                        ] => (
1471                            // We need to include the `::` in `Type::Variant::<Args>`
1472                            // to point the span to `::<Args>`, not just `<Args>`.
1473                            ident
1474                                .span
1475                                .shrink_to_hi()
1476                                .to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
1477                            false,
1478                        ),
1479                        [segment] => {
1480                            (
1481                                // We need to include the `::` in `Type::Variant::<Args>`
1482                                // to point the span to `::<Args>`, not just `<Args>`.
1483                                segment.ident.span.shrink_to_hi().to(segment
1484                                    .args
1485                                    .map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
1486                                kw::SelfUpper == segment.ident.name,
1487                            )
1488                        }
1489                        _ => {
1490                            err.note(msg);
1491                            return;
1492                        }
1493                    }
1494                } else {
1495                    err.note(msg);
1496                    return;
1497                };
1498            let suggestion = vec![
1499                if is_self {
1500                    // Account for people writing `Self::Variant::<Args>`, where
1501                    // `Self` is the enum, and suggest replacing `Self` with the
1502                    // appropriate type: `Type::<Args>::Variant`.
1503                    (qself.span, format!("{type_name}{snippet}"))
1504                } else {
1505                    (qself_sugg_span, snippet)
1506                },
1507                (args_span, String::new()),
1508            ];
1509            err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
1510        }
1511        GenericsArgsErrExtend::DefVariant(segments) => {
1512            let args: Vec<Span> = segments
1513                .iter()
1514                .filter_map(|segment| match segment.res {
1515                    Res::Def(
1516                        DefKind::Ctor(CtorOf::Variant, _) | DefKind::Variant | DefKind::Enum,
1517                        _,
1518                    ) => segment.args().span_ext().map(|s| s.with_lo(segment.ident.span.hi())),
1519                    _ => None,
1520                })
1521                .collect();
1522            if args.len() > 1
1523                && let Some(span) = args.into_iter().next_back()
1524            {
1525                err.note(
1526                    "generic arguments are not allowed on both an enum and its variant's path \
1527                     segments simultaneously; they are only valid in one place or the other",
1528                );
1529                err.span_suggestion_verbose(
1530                    span,
1531                    "remove the generics arguments from one of the path segments",
1532                    String::new(),
1533                    Applicability::MaybeIncorrect,
1534                );
1535            }
1536        }
1537        GenericsArgsErrExtend::PrimTy(prim_ty) => {
1538            let name = prim_ty.name_str();
1539            for segment in segments {
1540                if let Some(args) = segment.args {
1541                    err.span_suggestion_verbose(
1542                        segment.ident.span.shrink_to_hi().to(args.span_ext),
1543                        format!("primitive type `{name}` doesn't have generic parameters"),
1544                        "",
1545                        Applicability::MaybeIncorrect,
1546                    );
1547                }
1548            }
1549        }
1550        GenericsArgsErrExtend::OpaqueTy => {
1551            err.note("`impl Trait` types can't have type parameters");
1552        }
1553        GenericsArgsErrExtend::Param(def_id) => {
1554            let span = tcx.def_ident_span(def_id).unwrap();
1555            let kind = tcx.def_descr(def_id);
1556            let name = tcx.item_name(def_id);
1557            err.span_note(span, format!("{kind} `{name}` defined here"));
1558        }
1559        GenericsArgsErrExtend::SelfTyParam(span) => {
1560            err.span_suggestion_verbose(
1561                span,
1562                "the `Self` type doesn't accept type parameters",
1563                "",
1564                Applicability::MaybeIncorrect,
1565            );
1566        }
1567        GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
1568            let ty = tcx.at(span).type_of(def_id).instantiate_identity();
1569            let span_of_impl = tcx.span_of_impl(def_id);
1570            let def_id = match *ty.kind() {
1571                ty::Adt(self_def, _) => self_def.did(),
1572                _ => return,
1573            };
1574
1575            let type_name = tcx.item_name(def_id);
1576            let span_of_ty = tcx.def_ident_span(def_id);
1577            let generics = tcx.generics_of(def_id).count();
1578
1579            let msg = format!("`Self` is of type `{ty}`");
1580            if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
1581                let mut span: MultiSpan = vec![t_sp].into();
1582                span.push_span_label(
1583                    i_sp,
1584                    format!("`Self` is on type `{type_name}` in this `impl`"),
1585                );
1586                let mut postfix = "";
1587                if generics == 0 {
1588                    postfix = ", which doesn't have generic parameters";
1589                }
1590                span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
1591                err.span_note(span, msg);
1592            } else {
1593                err.note(msg);
1594            }
1595            for segment in segments {
1596                if let Some(args) = segment.args
1597                    && segment.ident.name == kw::SelfUpper
1598                {
1599                    if generics == 0 {
1600                        // FIXME(estebank): we could also verify that the arguments being
1601                        // work for the `enum`, instead of just looking if it takes *any*.
1602                        err.span_suggestion_verbose(
1603                            segment.ident.span.shrink_to_hi().to(args.span_ext),
1604                            "the `Self` type doesn't accept type parameters",
1605                            "",
1606                            Applicability::MachineApplicable,
1607                        );
1608                        return;
1609                    } else {
1610                        err.span_suggestion_verbose(
1611                            segment.ident.span,
1612                            format!(
1613                                "the `Self` type doesn't accept type parameters, use the \
1614                                concrete type's name `{type_name}` instead if you want to \
1615                                specify its type parameters"
1616                            ),
1617                            type_name,
1618                            Applicability::MaybeIncorrect,
1619                        );
1620                    }
1621                }
1622            }
1623        }
1624        _ => {}
1625    }
1626}
1627
1628pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
1629    match kind {
1630        ty::AssocKind::Fn => "function",
1631        ty::AssocKind::Const => "constant",
1632        ty::AssocKind::Type => "type",
1633    }
1634}