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