1use rustc_ast::TraitObjectSyntax;
2use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
3use rustc_errors::codes::*;
4use rustc_errors::{
5 Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, StashKey,
6 Suggestions, struct_span_code_err,
7};
8use rustc_hir::def::{DefKind, Res};
9use rustc_hir::def_id::DefId;
10use rustc_hir::{self as hir, HirId, LangItem};
11use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS};
12use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
13use rustc_middle::ty::{
14 self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
15 TypeVisitableExt, Upcast,
16};
17use rustc_span::edit_distance::find_best_match_for_name;
18use rustc_span::{ErrorGuaranteed, Span};
19use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
20use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
21use rustc_trait_selection::traits;
22use smallvec::{SmallVec, smallvec};
23use tracing::{debug, instrument};
24
25use super::HirTyLowerer;
26use crate::diagnostics::DynTraitAssocItemBindingMentionsSelf;
27use crate::hir_ty_lowering::{
28 GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints,
29 PredicateFilter, RegionInferReason,
30};
31
32impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
33 x;#[instrument(level = "debug", skip_all, ret)]
35 pub(super) fn lower_trait_object_ty(
36 &self,
37 span: Span,
38 hir_id: hir::HirId,
39 hir_bounds: &[hir::PolyTraitRef<'tcx>],
40 lifetime: &hir::Lifetime,
41 syntax: TraitObjectSyntax,
42 ) -> Ty<'tcx> {
43 let tcx = self.tcx();
44 let dummy_self = tcx.types.trait_object_dummy_self;
45
46 match syntax {
47 TraitObjectSyntax::Dyn => {}
48 TraitObjectSyntax::None => {
49 match self.prohibit_or_lint_bare_trait_object_ty(span, hir_id, hir_bounds) {
50 Some(guar) => return Ty::new_error(tcx, guar),
54 None => {}
55 }
56 }
57 }
58
59 let mut user_written_bounds = Vec::new();
60 let mut potential_assoc_items = Vec::new();
61 for poly_trait_ref in hir_bounds.iter() {
62 let result = self.lower_poly_trait_ref(
68 poly_trait_ref,
69 dummy_self,
70 &mut user_written_bounds,
71 PredicateFilter::SelfOnly,
72 OverlappingAsssocItemConstraints::Forbidden,
73 );
74 if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
75 potential_assoc_items.extend(invalid_args);
76 }
77 }
78
79 self.add_default_traits(
80 &mut user_written_bounds,
81 dummy_self,
82 &hir_bounds
83 .iter()
84 .map(|&trait_ref| hir::GenericBound::Trait(trait_ref))
85 .collect::<Vec<_>>(),
86 &[],
87 ImpliedBoundsContext::TraitObject,
88 span,
89 );
90
91 let (mut elaborated_trait_bounds, elaborated_projection_bounds) =
92 traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
93
94 debug!(?user_written_bounds, ?elaborated_trait_bounds);
96 let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
97 if user_written_bounds
100 .iter()
101 .all(|(clause, _)| clause.as_trait_clause().map(|p| p.def_id()) != Some(meta_sized_did))
102 {
103 elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did);
104 }
105 debug!(?user_written_bounds, ?elaborated_trait_bounds);
106
107 let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
108 .into_iter()
109 .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
110
111 if regular_traits.is_empty() && auto_traits.is_empty() {
113 let guar =
114 self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
115 return Ty::new_error(tcx, guar);
116 }
117 if regular_traits.len() > 1 {
119 let guar = self.report_trait_object_addition_traits(®ular_traits);
120 return Ty::new_error(tcx, guar);
121 }
122 if let Err(guar) = regular_traits.error_reported() {
124 return Ty::new_error(tcx, guar);
125 }
126
127 for (clause, span) in user_written_bounds {
131 if let Some(trait_pred) = clause.as_trait_clause() {
132 let violations = self.dyn_compatibility_violations(trait_pred.def_id());
133 if !violations.is_empty() {
134 let reported = report_dyn_incompatibility(
135 tcx,
136 span,
137 Some(hir_id),
138 trait_pred.def_id(),
139 &violations,
140 )
141 .emit();
142 return Ty::new_error(tcx, reported);
143 }
144 }
145 }
146
147 let mut projection_bounds = FxIndexMap::default();
157 for (proj, proj_span) in elaborated_projection_bounds {
158 let item_def_id = proj.item_def_id();
159
160 let proj = proj.map_bound(|mut proj| {
161 let references_self = proj.term.walk().any(|arg| arg == dummy_self.into());
162 if references_self {
163 let guar = self.dcx().emit_err(DynTraitAssocItemBindingMentionsSelf {
164 span,
165 kind: tcx.def_descr(item_def_id),
166 binding: proj_span,
167 });
168 proj.term = replace_dummy_self_with_error(tcx, proj.term, guar);
169 }
170 proj
171 });
172
173 let key = (
174 item_def_id,
175 tcx.anonymize_bound_vars(
176 proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
177 ),
178 );
179 if let Some((old_proj, old_proj_span)) =
180 projection_bounds.insert(key, (proj, proj_span))
181 && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
182 {
183 let kind = tcx.def_descr(item_def_id);
184 let name = tcx.item_name(item_def_id);
185 self.dcx()
186 .struct_span_err(span, format!("conflicting {kind} bindings for `{name}`"))
187 .with_span_label(
188 old_proj_span,
189 format!("`{name}` is specified to be `{}` here", old_proj.term()),
190 )
191 .with_span_label(
192 proj_span,
193 format!("`{name}` is specified to be `{}` here", proj.term()),
194 )
195 .emit();
196 }
197 }
198
199 let principal_trait = regular_traits.into_iter().next();
200
201 let mut ordered_associated_items = vec![];
207
208 if let Some((principal_trait, ref spans)) = principal_trait {
209 let principal_trait = principal_trait.map_bound(|trait_pred| {
210 assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
211 trait_pred.trait_ref
212 });
213
214 for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
215 tcx,
216 [ClauseWithSupertraitSpan::new(
217 ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
218 *spans.last().unwrap(),
219 )],
220 )
221 .filter_only_self()
222 {
223 let clause = clause.instantiate_supertrait(tcx, principal_trait);
224 debug!("observing object predicate `{clause:?}`");
225
226 let bound_predicate = clause.kind();
227 match bound_predicate.skip_binder() {
228 ty::ClauseKind::Trait(pred) => {
229 let trait_ref =
231 tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
232 ordered_associated_items.extend(
233 tcx.associated_items(pred.trait_ref.def_id)
234 .in_definition_order()
235 .filter(|item| item.is_type() || item.is_type_const())
238 .filter(|item| !item.is_impl_trait_in_trait())
240 .map(|item| (item.def_id, trait_ref)),
241 );
242 }
243 ty::ClauseKind::Projection(pred) => {
244 let pred = bound_predicate.rebind(pred);
245 let references_self =
248 pred.skip_binder().term.walk().any(|arg| arg == dummy_self.into());
249
250 if !references_self {
268 let key = (
269 pred.item_def_id(),
270 tcx.anonymize_bound_vars(
271 pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
272 ),
273 );
274 if !projection_bounds.contains_key(&key) {
275 projection_bounds.insert(key, (pred, supertrait_span));
276 }
277 }
278
279 self.check_elaborated_projection_mentions_input_lifetimes(
280 pred,
281 *spans.first().unwrap(),
282 supertrait_span,
283 );
284 }
285 _ => (),
286 }
287 }
288 }
289
290 for &(projection_bound, span) in projection_bounds.values() {
292 let def_id = projection_bound.item_def_id();
293 if tcx.generics_require_sized_self(def_id) {
294 tcx.emit_node_span_lint(
298 UNUSED_ASSOCIATED_TYPE_BOUNDS,
299 hir_id,
300 span,
301 crate::diagnostics::UnusedAssociatedTypeBounds { span },
302 );
303 }
304 }
305
306 let mut missing_assoc_items = FxIndexSet::default();
318 let projection_bounds: Vec<_> = ordered_associated_items
319 .into_iter()
320 .filter_map(|key @ (def_id, _)| {
321 if let Some(&assoc) = projection_bounds.get(&key) {
322 return Some(assoc);
323 }
324 if !tcx.generics_require_sized_self(def_id) {
325 missing_assoc_items.insert(key);
326 }
327 None
328 })
329 .collect();
330
331 if let Err(guar) = self.check_for_required_assoc_items(
333 principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
334 missing_assoc_items,
335 potential_assoc_items,
336 hir_bounds,
337 ) {
338 return Ty::new_error(tcx, guar);
339 }
340
341 let mut duplicates = FxHashSet::default();
346 auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
347
348 debug!(?principal_trait);
349 debug!(?auto_traits);
350
351 let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
353 trait_pred.map_bound(|trait_pred| {
354 let trait_ref = trait_pred.trait_ref;
355 assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
356 assert_eq!(trait_ref.self_ty(), dummy_self);
357
358 let span = *spans.first().unwrap();
359
360 let mut missing_generic_params = Vec::new();
363 let generics = tcx.generics_of(trait_ref.def_id);
364 let args: Vec<_> = trait_ref
365 .args
366 .iter()
367 .enumerate()
368 .skip(1)
370 .map(|(index, arg)| {
371 if arg.walk().any(|arg| arg == dummy_self.into()) {
372 let param = &generics.own_params[index];
373 missing_generic_params.push((param.name, param.kind.clone()));
374 param.to_error(tcx)
375 } else {
376 arg
377 }
378 })
379 .collect();
380
381 let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
382 hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
383 && hir_bound.span.contains(span)
384 });
385 self.report_missing_generic_params(
386 missing_generic_params,
387 trait_ref.def_id,
388 span,
389 empty_generic_args,
390 );
391
392 ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
393 tcx,
394 trait_ref.def_id,
395 args,
396 ))
397 })
398 });
399
400 let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
401 bound.map_bound(|mut b| {
402 assert_eq!(b.projection_term.self_ty(), dummy_self);
403
404 let references_self = b.projection_term.args.iter().skip(1).any(|arg| {
407 if arg.walk().any(|arg| arg == dummy_self.into()) {
408 return true;
409 }
410 false
411 });
412 if references_self {
413 let guar = tcx
414 .dcx()
415 .span_delayed_bug(span, "trait object projection bounds reference `Self`");
416 b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
417 }
418
419 ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
420 tcx, b,
421 ))
422 })
423 });
424
425 let mut auto_trait_predicates: Vec<_> = auto_traits
426 .into_iter()
427 .map(|(trait_pred, _)| {
428 assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
429 assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
430
431 ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
432 })
433 .collect();
434 auto_trait_predicates.dedup();
435
436 let mut predicates = principal_trait_ref
439 .into_iter()
440 .chain(existential_projections)
441 .chain(auto_trait_predicates)
442 .collect::<SmallVec<[_; 8]>>();
443 predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
444 let predicates = tcx.mk_poly_existential_predicates(&predicates);
445
446 let region_bound = self.lower_trait_object_lifetime(lifetime, predicates, span);
447
448 Ty::new_dynamic(tcx, predicates, region_bound)
449 }
450
451 fn lower_trait_object_lifetime(
452 &self,
453 lifetime: &hir::Lifetime,
454 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
455 span: Span,
456 ) -> ty::Region<'tcx> {
457 if let hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer =
460 lifetime.kind
461 && let Some(region) = self.compute_object_lifetime_bound(span, predicates)
462 {
463 return region;
464 }
465
466 let reason = if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind {
467 RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi())
468 } else {
469 RegionInferReason::ExplicitObjectLifetime
470 };
471
472 self.lower_lifetime(lifetime, reason)
473 }
474
475 fn check_elaborated_projection_mentions_input_lifetimes(
480 &self,
481 pred: ty::PolyProjectionPredicate<'tcx>,
482 span: Span,
483 supertrait_span: Span,
484 ) {
485 let tcx = self.tcx();
486
487 let late_bound_in_projection_term =
495 tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
496 let late_bound_in_term =
497 tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
498 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs:498",
"rustc_hir_analysis::hir_ty_lowering::dyn_trait",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs"),
::tracing_core::__macro_support::Option::Some(498u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::hir_ty_lowering::dyn_trait"),
::tracing_core::field::FieldSet::new(&["late_bound_in_projection_term"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&late_bound_in_projection_term)
as &dyn Value))])
});
} else { ; }
};debug!(?late_bound_in_projection_term);
499 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs:499",
"rustc_hir_analysis::hir_ty_lowering::dyn_trait",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs"),
::tracing_core::__macro_support::Option::Some(499u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::hir_ty_lowering::dyn_trait"),
::tracing_core::field::FieldSet::new(&["late_bound_in_term"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&late_bound_in_term)
as &dyn Value))])
});
} else { ; }
};debug!(?late_bound_in_term);
500
501 self.validate_late_bound_regions(
506 late_bound_in_projection_term,
507 late_bound_in_term,
508 |br_name| {
509 let item_name = tcx.item_name(pred.item_def_id());
510 {
self.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("binding for associated type `{0}` references {1}, which does not appear in the trait input types",
item_name, br_name))
})).with_code(E0582)
}struct_span_code_err!(
511 self.dcx(),
512 span,
513 E0582,
514 "binding for associated type `{}` references {}, \
515 which does not appear in the trait input types",
516 item_name,
517 br_name
518 )
519 .with_span_label(supertrait_span, "due to this supertrait")
520 },
521 );
522 }
523
524 x;#[instrument(level = "debug", skip(self, span), ret)]
532 fn compute_object_lifetime_bound(
533 &self,
534 span: Span,
535 existential_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
536 ) -> Option<ty::Region<'tcx>> {
538 let tcx = self.tcx();
539
540 let derived_region_bounds = traits::wf::object_region_bounds(tcx, existential_predicates);
543
544 if derived_region_bounds.is_empty() {
547 return None;
548 }
549
550 if derived_region_bounds.iter().any(|r| r.is_static()) {
553 return Some(tcx.lifetimes.re_static);
554 }
555
556 let r = derived_region_bounds[0];
560 if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
561 self.dcx().emit_err(crate::diagnostics::AmbiguousLifetimeBound { span });
562 }
563 Some(r)
564 }
565
566 fn prohibit_or_lint_bare_trait_object_ty(
571 &self,
572 span: Span,
573 hir_id: hir::HirId,
574 hir_bounds: &[hir::PolyTraitRef<'tcx>],
575 ) -> Option<ErrorGuaranteed> {
576 struct TraitObjectWithoutDyn<'a, 'tcx> {
577 span: Span,
578 hir_id: HirId,
579 sugg: Vec<(Span, String)>,
580 this: &'a dyn HirTyLowerer<'tcx>,
581 }
582
583 impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for TraitObjectWithoutDyn<'b, 'tcx> {
584 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
585 let Self { span, hir_id, sugg, this } = self;
586 let mut lint =
587 Diag::new(dcx, level, "trait objects without an explicit `dyn` are deprecated");
588 if span.can_be_used_for_suggestions() {
589 lint.multipart_suggestion(
590 "if this is a dyn-compatible trait, use `dyn`",
591 sugg,
592 Applicability::MachineApplicable,
593 );
594 }
595 this.maybe_suggest_blanket_trait_impl(span, hir_id, &mut lint);
596 lint
597 }
598 }
599
600 let tcx = self.tcx();
601 let [poly_trait_ref, ..] = hir_bounds else { return None };
602
603 let in_path = match tcx.parent_hir_node(hir_id) {
604 hir::Node::Ty(hir::Ty {
605 kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
606 ..
607 })
608 | hir::Node::Expr(hir::Expr {
609 kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
610 ..
611 })
612 | hir::Node::PatExpr(hir::PatExpr {
613 kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
614 ..
615 }) if qself.hir_id == hir_id => true,
616 _ => false,
617 };
618 let needs_bracket = in_path
619 && !tcx
620 .sess
621 .source_map()
622 .span_to_prev_source(span)
623 .ok()
624 .is_some_and(|s| s.trim_end().ends_with('<'));
625
626 let is_global = poly_trait_ref.trait_ref.path.is_global();
627
628 let mut sugg = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span.shrink_to_lo(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}dyn {1}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" }))
}))]))vec![(
629 span.shrink_to_lo(),
630 format!(
631 "{}dyn {}",
632 if needs_bracket { "<" } else { "" },
633 if is_global { "(" } else { "" },
634 ),
635 )];
636
637 if is_global || needs_bracket {
638 sugg.push((
639 span.shrink_to_hi(),
640 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" }))
})format!(
641 "{}{}",
642 if is_global { ")" } else { "" },
643 if needs_bracket { ">" } else { "" },
644 ),
645 ));
646 }
647
648 if span.edition().at_least_rust_2021() {
649 let mut diag = {
self.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}",
"expected a type, found a trait"))
})).with_code(E0782)
}rustc_errors::struct_span_code_err!(
650 self.dcx(),
651 span,
652 E0782,
653 "{}",
654 "expected a type, found a trait"
655 );
656 if span.can_be_used_for_suggestions()
657 && poly_trait_ref.trait_ref.trait_def_id().is_some()
658 && !self.maybe_suggest_impl_trait(span, hir_id, hir_bounds, &mut diag)
659 && !self.maybe_suggest_dyn_trait(hir_id, span, sugg, &mut diag)
660 {
661 self.maybe_suggest_add_generic_impl_trait(span, hir_id, &mut diag);
662 }
663 self.maybe_suggest_blanket_trait_impl(span, hir_id, &mut diag);
665 self.maybe_suggest_assoc_ty_bound(hir_id, &mut diag);
666 self.maybe_suggest_typoed_method(
667 hir_id,
668 poly_trait_ref.trait_ref.trait_def_id(),
669 &mut diag,
670 );
671 if let Some(mut sugg) =
674 self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion)
675 && let Suggestions::Enabled(ref mut s1) = diag.suggestions
676 && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
677 {
678 s1.append(s2);
679 sugg.cancel();
680 }
681 Some(diag.emit())
682 } else {
683 tcx.emit_node_span_lint(
684 BARE_TRAIT_OBJECTS,
685 hir_id,
686 span,
687 TraitObjectWithoutDyn { span, hir_id, sugg, this: self },
688 );
689 None
690 }
691 }
692
693 fn maybe_suggest_add_generic_impl_trait(
696 &self,
697 span: Span,
698 hir_id: hir::HirId,
699 diag: &mut Diag<'_>,
700 ) -> bool {
701 let tcx = self.tcx();
702
703 let parent_hir_id = tcx.parent_hir_id(hir_id);
704 let parent_item = tcx.hir_get_parent_item(hir_id).def_id;
705
706 let generics = match tcx.hir_node_by_def_id(parent_item) {
707 hir::Node::Item(hir::Item {
708 kind: hir::ItemKind::Struct(_, generics, variant),
709 ..
710 }) => {
711 if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
712 return false;
713 }
714 generics
715 }
716 hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
717 if !def
718 .variants
719 .iter()
720 .flat_map(|variant| variant.data.fields().iter())
721 .any(|field| field.hir_id == parent_hir_id)
722 {
723 return false;
724 }
725 generics
726 }
727 _ => return false,
728 };
729
730 let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(span) else {
731 return false;
732 };
733
734 let param = "TUV"
735 .chars()
736 .map(|c| c.to_string())
737 .chain((0..).map(|i| ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("P{0}", i)) })format!("P{i}")))
738 .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
739 .expect("we definitely can find at least one param name to generate");
740 let mut sugg = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span, param.to_string())]))vec![(span, param.to_string())];
741 if let Some(insertion_span) = generics.span_for_param_suggestion() {
742 sugg.push((insertion_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", {1}: {0}", rendered_ty, param))
})format!(", {param}: {}", rendered_ty)));
743 } else {
744 sugg.push((generics.where_clause_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{1}: {0}>", rendered_ty, param))
})format!("<{param}: {}>", rendered_ty)));
745 }
746 diag.multipart_suggestion(
747 "you might be missing a type parameter",
748 sugg,
749 Applicability::MachineApplicable,
750 );
751 true
752 }
753
754 fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
756 &self,
757 span: Span,
758 hir_id: hir::HirId,
759 diag: &mut Diag<'_, G>,
760 ) {
761 let tcx = self.tcx();
762 let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
763 if let hir::Node::Item(hir::Item {
764 kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
765 ..
766 }) = tcx.hir_node_by_def_id(parent_id)
767 && hir_id == impl_self_ty.hir_id
768 {
769 let Some(of_trait) = of_trait else {
770 diag.span_suggestion_verbose(
771 impl_self_ty.span.shrink_to_hi(),
772 "you might have intended to implement this trait for a given type",
773 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" for /* Type */"))
})format!(" for /* Type */"),
774 Applicability::HasPlaceholders,
775 );
776 return;
777 };
778 if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
779 return;
780 }
781 let of_trait_span = of_trait.trait_ref.path.span;
782 let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
784 return;
785 };
786
787 let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(span) else {
788 return;
789 };
790 let sugg = self.add_generic_param_suggestion(generics, span, &impl_trait_name);
791 diag.multipart_suggestion(
792 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("alternatively use a blanket implementation to implement `{0}` for all types that also implement `{1}`",
of_trait_name, impl_trait_name))
})format!(
793 "alternatively use a blanket implementation to implement `{of_trait_name}` for \
794 all types that also implement `{impl_trait_name}`"
795 ),
796 sugg,
797 Applicability::MaybeIncorrect,
798 );
799 }
800 }
801
802 fn maybe_suggest_dyn_trait(
810 &self,
811 hir_id: hir::HirId,
812 span: Span,
813 sugg: Vec<(Span, String)>,
814 diag: &mut Diag<'_>,
815 ) -> bool {
816 let tcx = self.tcx();
817 if span.in_derive_expansion() {
818 return false;
819 }
820
821 match tcx.parent_hir_node(hir_id) {
824 hir::Node::Ty(_)
830 | hir::Node::Expr(_)
831 | hir::Node::PatExpr(_)
832 | hir::Node::PathSegment(_)
833 | hir::Node::AssocItemConstraint(_)
834 | hir::Node::TraitRef(_)
835 | hir::Node::Item(_)
836 | hir::Node::WherePredicate(_) => {}
837
838 hir::Node::Field(field) => {
839 if let hir::Node::Item(hir::Item {
841 kind: hir::ItemKind::Struct(_, _, variant), ..
842 }) = tcx.parent_hir_node(field.hir_id)
843 && variant
844 .fields()
845 .last()
846 .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
847 {
848 } else {
850 return false;
851 }
852 }
853 _ => return false,
854 }
855
856 diag.multipart_suggestion(
858 "you can add the `dyn` keyword if you want a trait object",
859 sugg,
860 Applicability::MachineApplicable,
861 );
862 true
863 }
864
865 fn add_generic_param_suggestion(
866 &self,
867 generics: &hir::Generics<'_>,
868 self_ty_span: Span,
869 impl_trait_name: &str,
870 ) -> Vec<(Span, String)> {
871 let param_name = generics.params.next_type_param_name(None);
873
874 let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
875 (span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", {0}: {1}", param_name,
impl_trait_name))
})format!(", {param_name}: {impl_trait_name}"))
876 } else {
877 (generics.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}: {1}>", param_name,
impl_trait_name))
})format!("<{param_name}: {impl_trait_name}>"))
878 };
879 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(self_ty_span, param_name), add_generic_sugg]))vec![(self_ty_span, param_name), add_generic_sugg]
880 }
881
882 fn maybe_suggest_impl_trait(
884 &self,
885 span: Span,
886 hir_id: hir::HirId,
887 hir_bounds: &[hir::PolyTraitRef<'tcx>],
888 diag: &mut Diag<'_>,
889 ) -> bool {
890 let tcx = self.tcx();
891 let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
892 let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
899 hir::Node::Item(hir::Item {
900 kind: hir::ItemKind::Fn { sig, generics, .. }, ..
901 }) => (sig, generics),
902 hir::Node::TraitItem(hir::TraitItem {
903 kind: hir::TraitItemKind::Fn(sig, _),
904 generics,
905 ..
906 }) => (sig, generics),
907 hir::Node::ImplItem(hir::ImplItem {
908 kind: hir::ImplItemKind::Fn(sig, _),
909 generics,
910 ..
911 }) => (sig, generics),
912 _ => return false,
913 };
914 let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(span) else {
915 return false;
916 };
917 let impl_sugg = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span.shrink_to_lo(), "impl ".to_string())]))vec![(span.shrink_to_lo(), "impl ".to_string())];
918 let is_dyn_compatible = hir_bounds.iter().all(|bound| match bound.trait_ref.path.res {
920 Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
921 _ => false,
922 });
923
924 let borrowed = #[allow(non_exhaustive_omitted_patterns)] match tcx.parent_hir_node(hir_id) {
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. }) => true,
_ => false,
}matches!(
925 tcx.parent_hir_node(hir_id),
926 hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
927 );
928
929 if let hir::FnRetTy::Return(ty) = sig.decl.output
931 && ty.peel_refs().hir_id == hir_id
932 {
933 let pre = if !is_dyn_compatible {
934 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is dyn-incompatible, ",
trait_name))
})format!("`{trait_name}` is dyn-incompatible, ")
935 } else {
936 String::new()
937 };
938 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}use `impl {1}` to return an opaque type, as long as you return a single underlying type",
pre, trait_name))
})format!(
939 "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
940 single underlying type",
941 );
942
943 diag.multipart_suggestion(msg, impl_sugg, Applicability::MachineApplicable);
944
945 if is_dyn_compatible {
947 let suggestion = if borrowed {
951 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ty.span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Box<dyn {0}>",
trait_name))
}))]))vec![(ty.span, format!("Box<dyn {trait_name}>"))]
952 } else {
953 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
(ty.span.shrink_to_hi(), ">".to_string())]))vec![
954 (ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
955 (ty.span.shrink_to_hi(), ">".to_string()),
956 ]
957 };
958
959 diag.multipart_suggestion(
960 "alternatively, you can return an owned trait object",
961 suggestion,
962 Applicability::MachineApplicable,
963 );
964 }
965 return true;
966 }
967
968 for ty in sig.decl.inputs {
970 if ty.peel_refs().hir_id != hir_id {
971 continue;
972 }
973 let sugg = self.add_generic_param_suggestion(generics, span, &trait_name);
974 diag.multipart_suggestion(
975 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use a new generic type parameter, constrained by `{0}`",
trait_name))
})format!("use a new generic type parameter, constrained by `{trait_name}`"),
976 sugg,
977 Applicability::MachineApplicable,
978 );
979 diag.multipart_suggestion(
980 "you can also use an opaque type, but users won't be able to specify the type \
981 parameter when calling the `fn`, having to rely exclusively on type inference",
982 impl_sugg,
983 Applicability::MachineApplicable,
984 );
985 if !is_dyn_compatible {
986 diag.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is dyn-incompatible, otherwise a trait object could be used",
trait_name))
})format!(
987 "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
988 ));
989 } else {
990 let (dyn_str, paren_dyn_str) =
992 if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
993
994 let sugg = if let [_, _, ..] = hir_bounds {
995 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span.shrink_to_lo(), paren_dyn_str.to_string()),
(span.shrink_to_hi(), ")".to_string())]))vec![
997 (span.shrink_to_lo(), paren_dyn_str.to_string()),
998 (span.shrink_to_hi(), ")".to_string()),
999 ]
1000 } else {
1001 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span.shrink_to_lo(), dyn_str.to_string())]))vec![(span.shrink_to_lo(), dyn_str.to_string())]
1002 };
1003 diag.multipart_suggestion(
1004 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("alternatively, use a trait object to accept any type that implements `{0}`, accessing its methods at runtime using dynamic dispatch",
trait_name))
})format!(
1005 "alternatively, use a trait object to accept any type that implements \
1006 `{trait_name}`, accessing its methods at runtime using dynamic dispatch",
1007 ),
1008 sugg,
1009 Applicability::MachineApplicable,
1010 );
1011 }
1012 return true;
1013 }
1014 false
1015 }
1016
1017 fn maybe_suggest_assoc_ty_bound(&self, hir_id: hir::HirId, diag: &mut Diag<'_>) {
1018 let mut parents = self.tcx().hir_parent_iter(hir_id);
1019
1020 if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
1021 && let Some(obj_ty) = constraint.ty()
1022 && let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
1023 {
1024 if let Some((_, hir::Node::Ty(ty))) = parents.next()
1025 && let hir::TyKind::TraitObject(..) = ty.kind
1026 {
1027 return;
1029 }
1030
1031 if trait_ref
1032 .path
1033 .segments
1034 .iter()
1035 .find_map(|seg| {
1036 seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
1037 })
1038 .is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
1039 {
1040 return;
1042 }
1043
1044 let lo = if constraint.gen_args.span_ext.is_dummy() {
1045 constraint.ident.span
1046 } else {
1047 constraint.gen_args.span_ext
1048 };
1049 let hi = obj_ty.span;
1050
1051 if !lo.eq_ctxt(hi) {
1052 return;
1053 }
1054
1055 diag.span_suggestion_verbose(
1056 lo.between(hi),
1057 "you might have meant to write a bound here",
1058 ": ",
1059 Applicability::MaybeIncorrect,
1060 );
1061 }
1062 }
1063
1064 fn maybe_suggest_typoed_method(
1065 &self,
1066 hir_id: hir::HirId,
1067 trait_def_id: Option<DefId>,
1068 diag: &mut Diag<'_>,
1069 ) {
1070 let tcx = self.tcx();
1071 let Some(trait_def_id) = trait_def_id else {
1072 return;
1073 };
1074 let hir::Node::Expr(hir::Expr {
1075 kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
1076 ..
1077 }) = tcx.parent_hir_node(hir_id)
1078 else {
1079 return;
1080 };
1081 if path_ty.hir_id != hir_id {
1082 return;
1083 }
1084 let names: Vec<_> = tcx
1085 .associated_items(trait_def_id)
1086 .in_definition_order()
1087 .filter(|assoc| assoc.namespace() == hir::def::Namespace::ValueNS)
1088 .map(|cand| cand.name())
1089 .collect();
1090 if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
1091 diag.span_suggestion_verbose(
1092 segment.ident.span,
1093 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("you may have misspelled this associated item, causing `{0}` to be interpreted as a type rather than a trait",
tcx.item_name(trait_def_id)))
})format!(
1094 "you may have misspelled this associated item, causing `{}` \
1095 to be interpreted as a type rather than a trait",
1096 tcx.item_name(trait_def_id),
1097 ),
1098 typo,
1099 Applicability::MaybeIncorrect,
1100 );
1101 }
1102 }
1103}
1104
1105fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
1106 tcx: TyCtxt<'tcx>,
1107 t: T,
1108 guar: ErrorGuaranteed,
1109) -> T {
1110 t.fold_with(&mut BottomUpFolder {
1111 tcx,
1112 ty_op: |ty| {
1113 if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
1114 },
1115 lt_op: |lt| lt,
1116 ct_op: |ct| ct,
1117 })
1118}