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