rustc_hir_analysis/hir_ty_lowering/
dyn_trait.rs

1use rustc_ast::TraitObjectSyntax;
2use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
3use rustc_errors::codes::*;
4use rustc_errors::{
5    Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err,
6};
7use rustc_hir as hir;
8use rustc_hir::def::{DefKind, Res};
9use rustc_hir::def_id::DefId;
10use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS};
11use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
12use rustc_middle::ty::{
13    self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
14    TypeVisitableExt, Upcast,
15};
16use rustc_span::edit_distance::find_best_match_for_name;
17use rustc_span::{ErrorGuaranteed, Span};
18use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
19use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
20use rustc_trait_selection::traits;
21use smallvec::{SmallVec, smallvec};
22use tracing::{debug, instrument};
23
24use super::HirTyLowerer;
25use crate::errors::SelfInTypeAlias;
26use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
27
28impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
29    /// Lower a trait object type from the HIR to our internal notion of a type.
30    #[instrument(level = "debug", skip_all, ret)]
31    pub(super) fn lower_trait_object_ty(
32        &self,
33        span: Span,
34        hir_id: hir::HirId,
35        hir_bounds: &[hir::PolyTraitRef<'tcx>],
36        lifetime: &hir::Lifetime,
37        syntax: TraitObjectSyntax,
38    ) -> Ty<'tcx> {
39        let tcx = self.tcx();
40        let dummy_self = tcx.types.trait_object_dummy_self;
41
42        match syntax {
43            TraitObjectSyntax::Dyn => {}
44            TraitObjectSyntax::None => {
45                match self.prohibit_or_lint_bare_trait_object_ty(span, hir_id, hir_bounds) {
46                    // Don't continue with type analysis if the `dyn` keyword is missing.
47                    // It generates confusing errors, especially if the user meant to use
48                    // another keyword like `impl`.
49                    Some(guar) => return Ty::new_error(tcx, guar),
50                    None => {}
51                }
52            }
53        }
54
55        let mut user_written_bounds = Vec::new();
56        let mut potential_assoc_types = Vec::new();
57        for poly_trait_ref in hir_bounds.iter() {
58            let result = self.lower_poly_trait_ref(
59                poly_trait_ref,
60                dummy_self,
61                &mut user_written_bounds,
62                PredicateFilter::SelfOnly,
63            );
64            if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
65                potential_assoc_types.extend(invalid_args);
66            }
67        }
68
69        self.add_default_traits(
70            &mut user_written_bounds,
71            dummy_self,
72            &hir_bounds
73                .iter()
74                .map(|&trait_ref| hir::GenericBound::Trait(trait_ref))
75                .collect::<Vec<_>>(),
76            None,
77            span,
78        );
79
80        let (elaborated_trait_bounds, elaborated_projection_bounds) =
81            traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
82        let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
83            .into_iter()
84            .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
85
86        // We don't support empty trait objects.
87        if regular_traits.is_empty() && auto_traits.is_empty() {
88            let guar =
89                self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
90            return Ty::new_error(tcx, guar);
91        }
92        // We don't support >1 principal
93        if regular_traits.len() > 1 {
94            let guar = self.report_trait_object_addition_traits(&regular_traits);
95            return Ty::new_error(tcx, guar);
96        }
97        // Don't create a dyn trait if we have errors in the principal.
98        if let Err(guar) = regular_traits.error_reported() {
99            return Ty::new_error(tcx, guar);
100        }
101
102        // Check that there are no gross dyn-compatibility violations;
103        // most importantly, that the supertraits don't contain `Self`,
104        // to avoid ICEs.
105        for (clause, span) in user_written_bounds {
106            if let Some(trait_pred) = clause.as_trait_clause() {
107                let violations = self.dyn_compatibility_violations(trait_pred.def_id());
108                if !violations.is_empty() {
109                    let reported = report_dyn_incompatibility(
110                        tcx,
111                        span,
112                        Some(hir_id),
113                        trait_pred.def_id(),
114                        &violations,
115                    )
116                    .emit();
117                    return Ty::new_error(tcx, reported);
118                }
119            }
120        }
121
122        // Map the projection bounds onto a key that makes it easy to remove redundant
123        // bounds that are constrained by supertraits of the principal def id.
124        //
125        // Also make sure we detect conflicting bounds from expanding a trait alias and
126        // also specifying it manually, like:
127        // ```
128        // type Alias = Trait<Assoc = i32>;
129        // let _: &dyn Alias<Assoc = u32> = /* ... */;
130        // ```
131        let mut projection_bounds = FxIndexMap::default();
132        for (proj, proj_span) in elaborated_projection_bounds {
133            let proj = proj.map_bound(|mut b| {
134                if let Some(term_ty) = &b.term.as_type() {
135                    let references_self = term_ty.walk().any(|arg| arg == dummy_self.into());
136                    if references_self {
137                        // With trait alias and type alias combined, type resolver
138                        // may not be able to catch all illegal `Self` usages (issue 139082)
139                        let guar = self.dcx().emit_err(SelfInTypeAlias { span });
140                        b.term = replace_dummy_self_with_error(tcx, b.term, guar);
141                    }
142                }
143                b
144            });
145
146            let key = (
147                proj.skip_binder().projection_term.def_id,
148                tcx.anonymize_bound_vars(
149                    proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
150                ),
151            );
152            if let Some((old_proj, old_proj_span)) =
153                projection_bounds.insert(key, (proj, proj_span))
154                && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
155            {
156                let item = tcx.item_name(proj.item_def_id());
157                self.dcx()
158                    .struct_span_err(
159                        span,
160                        format!(
161                            "conflicting associated type bounds for `{item}` when \
162                            expanding trait alias"
163                        ),
164                    )
165                    .with_span_label(
166                        old_proj_span,
167                        format!("`{item}` is specified to be `{}` here", old_proj.term()),
168                    )
169                    .with_span_label(
170                        proj_span,
171                        format!("`{item}` is specified to be `{}` here", proj.term()),
172                    )
173                    .emit();
174            }
175        }
176
177        let principal_trait = regular_traits.into_iter().next();
178
179        // A stable ordering of associated types from the principal trait and all its
180        // supertraits. We use this to ensure that different substitutions of a trait
181        // don't result in `dyn Trait` types with different projections lists, which
182        // can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
183        // We achieve a stable ordering by walking over the unsubstituted principal
184        // trait ref.
185        let mut ordered_associated_types = vec![];
186
187        if let Some((principal_trait, ref spans)) = principal_trait {
188            let principal_trait = principal_trait.map_bound(|trait_pred| {
189                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
190                trait_pred.trait_ref
191            });
192
193            for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
194                tcx,
195                [ClauseWithSupertraitSpan::new(
196                    ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
197                    *spans.last().unwrap(),
198                )],
199            )
200            .filter_only_self()
201            {
202                let clause = clause.instantiate_supertrait(tcx, principal_trait);
203                debug!("observing object predicate `{clause:?}`");
204
205                let bound_predicate = clause.kind();
206                match bound_predicate.skip_binder() {
207                    ty::ClauseKind::Trait(pred) => {
208                        // FIXME(negative_bounds): Handle this correctly...
209                        let trait_ref =
210                            tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
211                        ordered_associated_types.extend(
212                            tcx.associated_items(pred.trait_ref.def_id)
213                                .in_definition_order()
214                                // We only care about associated types.
215                                .filter(|item| item.is_type())
216                                // No RPITITs -- they're not dyn-compatible for now.
217                                .filter(|item| !item.is_impl_trait_in_trait())
218                                .map(|item| (item.def_id, trait_ref)),
219                        );
220                    }
221                    ty::ClauseKind::Projection(pred) => {
222                        let pred = bound_predicate.rebind(pred);
223                        // A `Self` within the original bound will be instantiated with a
224                        // `trait_object_dummy_self`, so check for that.
225                        let references_self = match pred.skip_binder().term.kind() {
226                            ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
227                            // FIXME(associated_const_equality): We should walk the const instead of not doing anything
228                            ty::TermKind::Const(_) => false,
229                        };
230
231                        // If the projection output contains `Self`, force the user to
232                        // elaborate it explicitly to avoid a lot of complexity.
233                        //
234                        // The "classically useful" case is the following:
235                        // ```
236                        //     trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
237                        //         type MyOutput;
238                        //     }
239                        // ```
240                        //
241                        // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`,
242                        // but actually supporting that would "expand" to an infinitely-long type
243                        // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
244                        //
245                        // Instead, we force the user to write
246                        // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
247                        // the discussion in #56288 for alternatives.
248                        if !references_self {
249                            let key = (
250                                pred.skip_binder().projection_term.def_id,
251                                tcx.anonymize_bound_vars(
252                                    pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
253                                ),
254                            );
255                            if !projection_bounds.contains_key(&key) {
256                                projection_bounds.insert(key, (pred, supertrait_span));
257                            }
258                        }
259
260                        self.check_elaborated_projection_mentions_input_lifetimes(
261                            pred,
262                            *spans.first().unwrap(),
263                            supertrait_span,
264                        );
265                    }
266                    _ => (),
267                }
268            }
269        }
270
271        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
272        // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
273        // `Assoc = Foo` bound. `needed_associated_types` contains all associated
274        // types that we expect to be provided by the user, so the following loop
275        // removes all the associated types that have a corresponding `Projection`
276        // clause, either from expanding trait aliases or written by the user.
277        for &(projection_bound, span) in projection_bounds.values() {
278            let def_id = projection_bound.item_def_id();
279            if tcx.generics_require_sized_self(def_id) {
280                tcx.emit_node_span_lint(
281                    UNUSED_ASSOCIATED_TYPE_BOUNDS,
282                    hir_id,
283                    span,
284                    crate::errors::UnusedAssociatedTypeBounds { span },
285                );
286            }
287        }
288
289        // We compute the list of projection bounds taking the ordered associated types,
290        // and check if there was an entry in the collected `projection_bounds`. Those
291        // are computed by first taking the user-written associated types, then elaborating
292        // the principal trait ref, and only using those if there was no user-written.
293        // See note below about how we handle missing associated types with `Self: Sized`,
294        // which are not required to be provided, but are still used if they are provided.
295        let mut missing_assoc_types = FxIndexSet::default();
296        let projection_bounds: Vec<_> = ordered_associated_types
297            .into_iter()
298            .filter_map(|key| {
299                if let Some(assoc) = projection_bounds.get(&key) {
300                    Some(*assoc)
301                } else {
302                    // If the associated type has a `where Self: Sized` bound, then
303                    // we do not need to provide the associated type. This results in
304                    // a `dyn Trait` type that has a different number of projection
305                    // bounds, which may lead to type mismatches.
306                    if !tcx.generics_require_sized_self(key.0) {
307                        missing_assoc_types.insert(key);
308                    }
309                    None
310                }
311            })
312            .collect();
313
314        if let Err(guar) = self.check_for_required_assoc_tys(
315            principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
316            missing_assoc_types,
317            potential_assoc_types,
318            hir_bounds,
319        ) {
320            return Ty::new_error(tcx, guar);
321        }
322
323        // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
324        // `dyn Trait + Send`.
325        // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
326        // the bounds
327        let mut duplicates = FxHashSet::default();
328        auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
329
330        debug!(?principal_trait);
331        debug!(?auto_traits);
332
333        // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
334        let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
335            trait_pred.map_bound(|trait_pred| {
336                let trait_ref = trait_pred.trait_ref;
337                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
338                assert_eq!(trait_ref.self_ty(), dummy_self);
339
340                let span = *spans.first().unwrap();
341
342                // Verify that `dummy_self` did not leak inside default type parameters. This
343                // could not be done at path creation, since we need to see through trait aliases.
344                let mut missing_type_params = vec![];
345                let generics = tcx.generics_of(trait_ref.def_id);
346                let args: Vec<_> = trait_ref
347                    .args
348                    .iter()
349                    .enumerate()
350                    // Skip `Self`
351                    .skip(1)
352                    .map(|(index, arg)| {
353                        if arg.walk().any(|arg| arg == dummy_self.into()) {
354                            let param = &generics.own_params[index];
355                            missing_type_params.push(param.name);
356                            Ty::new_misc_error(tcx).into()
357                        } else {
358                            arg
359                        }
360                    })
361                    .collect();
362
363                let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
364                    hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
365                        && hir_bound.span.contains(span)
366                });
367                self.report_missing_type_params(
368                    missing_type_params,
369                    trait_ref.def_id,
370                    span,
371                    empty_generic_args,
372                );
373
374                ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
375                    tcx,
376                    trait_ref.def_id,
377                    args,
378                ))
379            })
380        });
381
382        let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
383            bound.map_bound(|mut b| {
384                assert_eq!(b.projection_term.self_ty(), dummy_self);
385
386                // Like for trait refs, verify that `dummy_self` did not leak inside default type
387                // parameters.
388                let references_self = b.projection_term.args.iter().skip(1).any(|arg| {
389                    if arg.walk().any(|arg| arg == dummy_self.into()) {
390                        return true;
391                    }
392                    false
393                });
394                if references_self {
395                    let guar = tcx
396                        .dcx()
397                        .span_delayed_bug(span, "trait object projection bounds reference `Self`");
398                    b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
399                }
400
401                ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
402                    tcx, b,
403                ))
404            })
405        });
406
407        let mut auto_trait_predicates: Vec<_> = auto_traits
408            .into_iter()
409            .map(|(trait_pred, _)| {
410                assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
411                assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
412
413                ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
414            })
415            .collect();
416        auto_trait_predicates.dedup();
417
418        // N.b. principal, projections, auto traits
419        // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
420        let mut v = principal_trait_ref
421            .into_iter()
422            .chain(existential_projections)
423            .chain(auto_trait_predicates)
424            .collect::<SmallVec<[_; 8]>>();
425        v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
426        let existential_predicates = tcx.mk_poly_existential_predicates(&v);
427
428        // Use explicitly-specified region bound, unless the bound is missing.
429        let region_bound = if !lifetime.is_elided() {
430            self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
431        } else {
432            self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
433                // Curiously, we prefer object lifetime default for `+ '_`...
434                if tcx.named_bound_var(lifetime.hir_id).is_some() {
435                    self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
436                } else {
437                    let reason =
438                        if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind {
439                            if let hir::Node::Ty(hir::Ty {
440                                kind: hir::TyKind::Ref(parent_lifetime, _),
441                                ..
442                            }) = tcx.parent_hir_node(hir_id)
443                                && tcx.named_bound_var(parent_lifetime.hir_id).is_none()
444                            {
445                                // Parent lifetime must have failed to resolve. Don't emit a redundant error.
446                                RegionInferReason::ExplicitObjectLifetime
447                            } else {
448                                RegionInferReason::ObjectLifetimeDefault
449                            }
450                        } else {
451                            RegionInferReason::ExplicitObjectLifetime
452                        };
453                    self.re_infer(span, reason)
454                }
455            })
456        };
457        debug!(?region_bound);
458
459        Ty::new_dynamic(tcx, existential_predicates, region_bound)
460    }
461
462    /// Check that elaborating the principal of a trait ref doesn't lead to projections
463    /// that are unconstrained. This can happen because an otherwise unconstrained
464    /// *type variable* can be substituted with a type that has late-bound regions. See
465    /// `elaborated-predicates-unconstrained-late-bound.rs` for a test.
466    fn check_elaborated_projection_mentions_input_lifetimes(
467        &self,
468        pred: ty::PolyProjectionPredicate<'tcx>,
469        span: Span,
470        supertrait_span: Span,
471    ) {
472        let tcx = self.tcx();
473
474        // Find any late-bound regions declared in `ty` that are not
475        // declared in the trait-ref or assoc_item. These are not well-formed.
476        //
477        // Example:
478        //
479        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
480        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
481        let late_bound_in_projection_term =
482            tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
483        let late_bound_in_term =
484            tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
485        debug!(?late_bound_in_projection_term);
486        debug!(?late_bound_in_term);
487
488        // FIXME: point at the type params that don't have appropriate lifetimes:
489        // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
490        //                         ----  ----     ^^^^^^^
491        // NOTE(associated_const_equality): This error should be impossible to trigger
492        //                                  with associated const equality constraints.
493        self.validate_late_bound_regions(
494            late_bound_in_projection_term,
495            late_bound_in_term,
496            |br_name| {
497                let item_name = tcx.item_name(pred.item_def_id());
498                struct_span_code_err!(
499                    self.dcx(),
500                    span,
501                    E0582,
502                    "binding for associated type `{}` references {}, \
503                             which does not appear in the trait input types",
504                    item_name,
505                    br_name
506                )
507                .with_span_label(supertrait_span, "due to this supertrait")
508            },
509        );
510    }
511
512    /// Prohibit or lint against *bare* trait object types depending on the edition.
513    ///
514    /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
515    /// In edition 2021 and onward we emit a hard error for them.
516    fn prohibit_or_lint_bare_trait_object_ty(
517        &self,
518        span: Span,
519        hir_id: hir::HirId,
520        hir_bounds: &[hir::PolyTraitRef<'tcx>],
521    ) -> Option<ErrorGuaranteed> {
522        let tcx = self.tcx();
523        let [poly_trait_ref, ..] = hir_bounds else { return None };
524
525        let in_path = match tcx.parent_hir_node(hir_id) {
526            hir::Node::Ty(hir::Ty {
527                kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
528                ..
529            })
530            | hir::Node::Expr(hir::Expr {
531                kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
532                ..
533            })
534            | hir::Node::PatExpr(hir::PatExpr {
535                kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
536                ..
537            }) if qself.hir_id == hir_id => true,
538            _ => false,
539        };
540        let needs_bracket = in_path
541            && !tcx
542                .sess
543                .source_map()
544                .span_to_prev_source(span)
545                .ok()
546                .is_some_and(|s| s.trim_end().ends_with('<'));
547
548        let is_global = poly_trait_ref.trait_ref.path.is_global();
549
550        let mut sugg = vec![(
551            span.shrink_to_lo(),
552            format!(
553                "{}dyn {}",
554                if needs_bracket { "<" } else { "" },
555                if is_global { "(" } else { "" },
556            ),
557        )];
558
559        if is_global || needs_bracket {
560            sugg.push((
561                span.shrink_to_hi(),
562                format!(
563                    "{}{}",
564                    if is_global { ")" } else { "" },
565                    if needs_bracket { ">" } else { "" },
566                ),
567            ));
568        }
569
570        if span.edition().at_least_rust_2021() {
571            let mut diag = rustc_errors::struct_span_code_err!(
572                self.dcx(),
573                span,
574                E0782,
575                "{}",
576                "expected a type, found a trait"
577            );
578            if span.can_be_used_for_suggestions()
579                && poly_trait_ref.trait_ref.trait_def_id().is_some()
580                && !self.maybe_suggest_impl_trait(span, hir_id, hir_bounds, &mut diag)
581                && !self.maybe_suggest_dyn_trait(hir_id, sugg, &mut diag)
582            {
583                self.maybe_suggest_add_generic_impl_trait(span, hir_id, &mut diag);
584            }
585            // Check if the impl trait that we are considering is an impl of a local trait.
586            self.maybe_suggest_blanket_trait_impl(span, hir_id, &mut diag);
587            self.maybe_suggest_assoc_ty_bound(hir_id, &mut diag);
588            self.maybe_suggest_typoed_method(
589                hir_id,
590                poly_trait_ref.trait_ref.trait_def_id(),
591                &mut diag,
592            );
593            // In case there is an associated type with the same name
594            // Add the suggestion to this error
595            if let Some(mut sugg) =
596                self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion)
597                && let Suggestions::Enabled(ref mut s1) = diag.suggestions
598                && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
599            {
600                s1.append(s2);
601                sugg.cancel();
602            }
603            Some(diag.emit())
604        } else {
605            tcx.node_span_lint(BARE_TRAIT_OBJECTS, hir_id, span, |lint| {
606                lint.primary_message("trait objects without an explicit `dyn` are deprecated");
607                if span.can_be_used_for_suggestions() {
608                    lint.multipart_suggestion_verbose(
609                        "if this is a dyn-compatible trait, use `dyn`",
610                        sugg,
611                        Applicability::MachineApplicable,
612                    );
613                }
614                self.maybe_suggest_blanket_trait_impl(span, hir_id, lint);
615            });
616            None
617        }
618    }
619
620    /// For a struct or enum with an invalid bare trait object field, suggest turning
621    /// it into a generic type bound.
622    fn maybe_suggest_add_generic_impl_trait(
623        &self,
624        span: Span,
625        hir_id: hir::HirId,
626        diag: &mut Diag<'_>,
627    ) -> bool {
628        let tcx = self.tcx();
629
630        let parent_hir_id = tcx.parent_hir_id(hir_id);
631        let parent_item = tcx.hir_get_parent_item(hir_id).def_id;
632
633        let generics = match tcx.hir_node_by_def_id(parent_item) {
634            hir::Node::Item(hir::Item {
635                kind: hir::ItemKind::Struct(_, generics, variant),
636                ..
637            }) => {
638                if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
639                    return false;
640                }
641                generics
642            }
643            hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
644                if !def
645                    .variants
646                    .iter()
647                    .flat_map(|variant| variant.data.fields().iter())
648                    .any(|field| field.hir_id == parent_hir_id)
649                {
650                    return false;
651                }
652                generics
653            }
654            _ => return false,
655        };
656
657        let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(span) else {
658            return false;
659        };
660
661        let param = "TUV"
662            .chars()
663            .map(|c| c.to_string())
664            .chain((0..).map(|i| format!("P{i}")))
665            .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
666            .expect("we definitely can find at least one param name to generate");
667        let mut sugg = vec![(span, param.to_string())];
668        if let Some(insertion_span) = generics.span_for_param_suggestion() {
669            sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
670        } else {
671            sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
672        }
673        diag.multipart_suggestion_verbose(
674            "you might be missing a type parameter",
675            sugg,
676            Applicability::MachineApplicable,
677        );
678        true
679    }
680
681    /// Make sure that we are in the condition to suggest the blanket implementation.
682    fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
683        &self,
684        span: Span,
685        hir_id: hir::HirId,
686        diag: &mut Diag<'_, G>,
687    ) {
688        let tcx = self.tcx();
689        let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
690        if let hir::Node::Item(hir::Item {
691            kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
692            ..
693        }) = tcx.hir_node_by_def_id(parent_id)
694            && hir_id == impl_self_ty.hir_id
695        {
696            let Some(of_trait) = of_trait else {
697                diag.span_suggestion_verbose(
698                    impl_self_ty.span.shrink_to_hi(),
699                    "you might have intended to implement this trait for a given type",
700                    format!(" for /* Type */"),
701                    Applicability::HasPlaceholders,
702                );
703                return;
704            };
705            if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
706                return;
707            }
708            let of_trait_span = of_trait.trait_ref.path.span;
709            // make sure that we are not calling unwrap to abort during the compilation
710            let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
711                return;
712            };
713
714            let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(span) else {
715                return;
716            };
717            let sugg = self.add_generic_param_suggestion(generics, span, &impl_trait_name);
718            diag.multipart_suggestion(
719                format!(
720                    "alternatively use a blanket implementation to implement `{of_trait_name}` for \
721                     all types that also implement `{impl_trait_name}`"
722                ),
723                sugg,
724                Applicability::MaybeIncorrect,
725            );
726        }
727    }
728
729    /// Try our best to approximate when adding `dyn` would be helpful for a bare
730    /// trait object.
731    ///
732    /// Right now, this is if the type is either directly nested in another ty,
733    /// or if it's in the tail field within a struct. This approximates what the
734    /// user would've gotten on edition 2015, except for the case where we have
735    /// an *obvious* knock-on `Sized` error.
736    fn maybe_suggest_dyn_trait(
737        &self,
738        hir_id: hir::HirId,
739        sugg: Vec<(Span, String)>,
740        diag: &mut Diag<'_>,
741    ) -> bool {
742        let tcx = self.tcx();
743
744        // Look at the direct HIR parent, since we care about the relationship between
745        // the type and the thing that directly encloses it.
746        match tcx.parent_hir_node(hir_id) {
747            // These are all generally ok. Namely, when a trait object is nested
748            // into another expression or ty, it's either very certain that they
749            // missed the ty (e.g. `&Trait`) or it's not really possible to tell
750            // what their intention is, so let's not give confusing suggestions and
751            // just mention `dyn`. The user can make up their mind what to do here.
752            hir::Node::Ty(_)
753            | hir::Node::Expr(_)
754            | hir::Node::PatExpr(_)
755            | hir::Node::PathSegment(_)
756            | hir::Node::AssocItemConstraint(_)
757            | hir::Node::TraitRef(_)
758            | hir::Node::Item(_)
759            | hir::Node::WherePredicate(_) => {}
760
761            hir::Node::Field(field) => {
762                // Enums can't have unsized fields, fields can only have an unsized tail field.
763                if let hir::Node::Item(hir::Item {
764                    kind: hir::ItemKind::Struct(_, _, variant), ..
765                }) = tcx.parent_hir_node(field.hir_id)
766                    && variant
767                        .fields()
768                        .last()
769                        .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
770                {
771                    // Ok
772                } else {
773                    return false;
774                }
775            }
776            _ => return false,
777        }
778
779        // FIXME: Only emit this suggestion if the trait is dyn-compatible.
780        diag.multipart_suggestion_verbose(
781            "you can add the `dyn` keyword if you want a trait object",
782            sugg,
783            Applicability::MachineApplicable,
784        );
785        true
786    }
787
788    fn add_generic_param_suggestion(
789        &self,
790        generics: &hir::Generics<'_>,
791        self_ty_span: Span,
792        impl_trait_name: &str,
793    ) -> Vec<(Span, String)> {
794        // check if the trait has generics, to make a correct suggestion
795        let param_name = generics.params.next_type_param_name(None);
796
797        let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
798            (span, format!(", {param_name}: {impl_trait_name}"))
799        } else {
800            (generics.span, format!("<{param_name}: {impl_trait_name}>"))
801        };
802        vec![(self_ty_span, param_name), add_generic_sugg]
803    }
804
805    /// Make sure that we are in the condition to suggest `impl Trait`.
806    fn maybe_suggest_impl_trait(
807        &self,
808        span: Span,
809        hir_id: hir::HirId,
810        hir_bounds: &[hir::PolyTraitRef<'tcx>],
811        diag: &mut Diag<'_>,
812    ) -> bool {
813        let tcx = self.tcx();
814        let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
815        // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
816        //        and suggest `Trait0<Ty = impl Trait1>`.
817        // Functions are found in three different contexts.
818        // 1. Independent functions
819        // 2. Functions inside trait blocks
820        // 3. Functions inside impl blocks
821        let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
822            hir::Node::Item(hir::Item {
823                kind: hir::ItemKind::Fn { sig, generics, .. }, ..
824            }) => (sig, generics),
825            hir::Node::TraitItem(hir::TraitItem {
826                kind: hir::TraitItemKind::Fn(sig, _),
827                generics,
828                ..
829            }) => (sig, generics),
830            hir::Node::ImplItem(hir::ImplItem {
831                kind: hir::ImplItemKind::Fn(sig, _),
832                generics,
833                ..
834            }) => (sig, generics),
835            _ => return false,
836        };
837        let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(span) else {
838            return false;
839        };
840        let impl_sugg = vec![(span.shrink_to_lo(), "impl ".to_string())];
841        // Check if trait object is safe for suggesting dynamic dispatch.
842        let is_dyn_compatible = hir_bounds.iter().all(|bound| match bound.trait_ref.path.res {
843            Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
844            _ => false,
845        });
846
847        let borrowed = matches!(
848            tcx.parent_hir_node(hir_id),
849            hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
850        );
851
852        // Suggestions for function return type.
853        if let hir::FnRetTy::Return(ty) = sig.decl.output
854            && ty.peel_refs().hir_id == hir_id
855        {
856            let pre = if !is_dyn_compatible {
857                format!("`{trait_name}` is dyn-incompatible, ")
858            } else {
859                String::new()
860            };
861            let msg = format!(
862                "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
863                 single underlying type",
864            );
865
866            diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
867
868            // Suggest `Box<dyn Trait>` for return type
869            if is_dyn_compatible {
870                // If the return type is `&Trait`, we don't want
871                // the ampersand to be displayed in the `Box<dyn Trait>`
872                // suggestion.
873                let suggestion = if borrowed {
874                    vec![(ty.span, format!("Box<dyn {trait_name}>"))]
875                } else {
876                    vec![
877                        (ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
878                        (ty.span.shrink_to_hi(), ">".to_string()),
879                    ]
880                };
881
882                diag.multipart_suggestion_verbose(
883                    "alternatively, you can return an owned trait object",
884                    suggestion,
885                    Applicability::MachineApplicable,
886                );
887            }
888            return true;
889        }
890
891        // Suggestions for function parameters.
892        for ty in sig.decl.inputs {
893            if ty.peel_refs().hir_id != hir_id {
894                continue;
895            }
896            let sugg = self.add_generic_param_suggestion(generics, span, &trait_name);
897            diag.multipart_suggestion_verbose(
898                format!("use a new generic type parameter, constrained by `{trait_name}`"),
899                sugg,
900                Applicability::MachineApplicable,
901            );
902            diag.multipart_suggestion_verbose(
903                "you can also use an opaque type, but users won't be able to specify the type \
904                 parameter when calling the `fn`, having to rely exclusively on type inference",
905                impl_sugg,
906                Applicability::MachineApplicable,
907            );
908            if !is_dyn_compatible {
909                diag.note(format!(
910                    "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
911                ));
912            } else {
913                // No ampersand in suggestion if it's borrowed already
914                let (dyn_str, paren_dyn_str) =
915                    if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
916
917                let sugg = if let [_, _, ..] = hir_bounds {
918                    // There is more than one trait bound, we need surrounding parentheses.
919                    vec![
920                        (span.shrink_to_lo(), paren_dyn_str.to_string()),
921                        (span.shrink_to_hi(), ")".to_string()),
922                    ]
923                } else {
924                    vec![(span.shrink_to_lo(), dyn_str.to_string())]
925                };
926                diag.multipart_suggestion_verbose(
927                    format!(
928                        "alternatively, use a trait object to accept any type that implements \
929                         `{trait_name}`, accessing its methods at runtime using dynamic dispatch",
930                    ),
931                    sugg,
932                    Applicability::MachineApplicable,
933                );
934            }
935            return true;
936        }
937        false
938    }
939
940    fn maybe_suggest_assoc_ty_bound(&self, hir_id: hir::HirId, diag: &mut Diag<'_>) {
941        let mut parents = self.tcx().hir_parent_iter(hir_id);
942
943        if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
944            && let Some(obj_ty) = constraint.ty()
945            && let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
946        {
947            if let Some((_, hir::Node::Ty(ty))) = parents.next()
948                && let hir::TyKind::TraitObject(..) = ty.kind
949            {
950                // Assoc ty bounds aren't permitted inside trait object types.
951                return;
952            }
953
954            if trait_ref
955                .path
956                .segments
957                .iter()
958                .find_map(|seg| {
959                    seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
960                })
961                .is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
962            {
963                // Only consider angle-bracketed args (where we have a `=` to replace with `:`).
964                return;
965            }
966
967            let lo = if constraint.gen_args.span_ext.is_dummy() {
968                constraint.ident.span
969            } else {
970                constraint.gen_args.span_ext
971            };
972            let hi = obj_ty.span;
973
974            if !lo.eq_ctxt(hi) {
975                return;
976            }
977
978            diag.span_suggestion_verbose(
979                lo.between(hi),
980                "you might have meant to write a bound here",
981                ": ",
982                Applicability::MaybeIncorrect,
983            );
984        }
985    }
986
987    fn maybe_suggest_typoed_method(
988        &self,
989        hir_id: hir::HirId,
990        trait_def_id: Option<DefId>,
991        diag: &mut Diag<'_>,
992    ) {
993        let tcx = self.tcx();
994        let Some(trait_def_id) = trait_def_id else {
995            return;
996        };
997        let hir::Node::Expr(hir::Expr {
998            kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
999            ..
1000        }) = tcx.parent_hir_node(hir_id)
1001        else {
1002            return;
1003        };
1004        if path_ty.hir_id != hir_id {
1005            return;
1006        }
1007        let names: Vec<_> = tcx
1008            .associated_items(trait_def_id)
1009            .in_definition_order()
1010            .filter(|assoc| assoc.namespace() == hir::def::Namespace::ValueNS)
1011            .map(|cand| cand.name())
1012            .collect();
1013        if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
1014            diag.span_suggestion_verbose(
1015                segment.ident.span,
1016                format!(
1017                    "you may have misspelled this associated item, causing `{}` \
1018                    to be interpreted as a type rather than a trait",
1019                    tcx.item_name(trait_def_id),
1020                ),
1021                typo,
1022                Applicability::MaybeIncorrect,
1023            );
1024        }
1025    }
1026}
1027
1028fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
1029    tcx: TyCtxt<'tcx>,
1030    t: T,
1031    guar: ErrorGuaranteed,
1032) -> T {
1033    t.fold_with(&mut BottomUpFolder {
1034        tcx,
1035        ty_op: |ty| {
1036            if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
1037        },
1038        lt_op: |lt| lt,
1039        ct_op: |ct| ct,
1040    })
1041}