Skip to main content

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