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