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