rustc_hir_analysis/hir_ty_lowering/
errors.rs

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