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 #[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 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 debug!(?user_written_bounds, ?elaborated_trait_bounds);
89 let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
90 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 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 if regular_traits.len() > 1 {
112 let guar = self.report_trait_object_addition_traits(®ular_traits);
113 return Ty::new_error(tcx, guar);
114 }
115 if let Err(guar) = regular_traits.error_reported() {
117 return Ty::new_error(tcx, guar);
118 }
119
120 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 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 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 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 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 .filter(|item| item.is_type())
231 .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 let references_self = match pred.skip_binder().term.kind() {
241 ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
242 ty::TermKind::Const(_) => false,
244 };
245
246 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 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 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 !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 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 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 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(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 match tcx.parent_hir_node(hir_id) {
762 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 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 } else {
788 return false;
789 }
790 }
791 _ => return false,
792 }
793
794 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 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 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 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 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 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 if is_dyn_compatible {
885 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 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 let (dyn_str, paren_dyn_str) =
930 if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
931
932 let sugg = if let [_, _, ..] = hir_bounds {
933 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 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 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}