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 #[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 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 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 if regular_traits.len() > 1 {
94 let guar = self.report_trait_object_addition_traits(®ular_traits);
95 return Ty::new_error(tcx, guar);
96 }
97 if let Err(guar) = regular_traits.error_reported() {
99 return Ty::new_error(tcx, guar);
100 }
101
102 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 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 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 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 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 .filter(|item| item.is_type())
216 .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 let references_self = match pred.skip_binder().term.kind() {
226 ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
227 ty::TermKind::Const(_) => false,
229 };
230
231 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 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 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 !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 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 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 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(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 match tcx.parent_hir_node(hir_id) {
747 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 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 } else {
773 return false;
774 }
775 }
776 _ => return false,
777 }
778
779 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 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 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 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 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 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 if is_dyn_compatible {
870 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 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 let (dyn_str, paren_dyn_str) =
915 if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
916
917 let sugg = if let [_, _, ..] = hir_bounds {
918 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 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 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}