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