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