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::DynTraitAssocItemBindingMentionsSelf;
26use crate::hir_ty_lowering::{
27 GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints,
28 PredicateFilter, RegionInferReason,
29};
30
31impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
32 x;#[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_items = Vec::new();
60 for poly_trait_ref in hir_bounds.iter() {
61 let result = self.lower_poly_trait_ref(
67 poly_trait_ref,
68 dummy_self,
69 &mut user_written_bounds,
70 PredicateFilter::SelfOnly,
71 OverlappingAsssocItemConstraints::Forbidden,
72 );
73 if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
74 potential_assoc_items.extend(invalid_args);
75 }
76 }
77
78 self.add_default_traits(
79 &mut user_written_bounds,
80 dummy_self,
81 &hir_bounds
82 .iter()
83 .map(|&trait_ref| hir::GenericBound::Trait(trait_ref))
84 .collect::<Vec<_>>(),
85 ImpliedBoundsContext::AssociatedTypeOrImplTrait,
86 span,
87 );
88
89 let (mut elaborated_trait_bounds, elaborated_projection_bounds) =
90 traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
91
92 debug!(?user_written_bounds, ?elaborated_trait_bounds);
94 let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
95 if user_written_bounds
98 .iter()
99 .all(|(clause, _)| clause.as_trait_clause().map(|p| p.def_id()) != Some(meta_sized_did))
100 {
101 elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did);
102 }
103 debug!(?user_written_bounds, ?elaborated_trait_bounds);
104
105 let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
106 .into_iter()
107 .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
108
109 if regular_traits.is_empty() && auto_traits.is_empty() {
111 let guar =
112 self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
113 return Ty::new_error(tcx, guar);
114 }
115 if regular_traits.len() > 1 {
117 let guar = self.report_trait_object_addition_traits(®ular_traits);
118 return Ty::new_error(tcx, guar);
119 }
120 if let Err(guar) = regular_traits.error_reported() {
122 return Ty::new_error(tcx, guar);
123 }
124
125 for (clause, span) in user_written_bounds {
129 if let Some(trait_pred) = clause.as_trait_clause() {
130 let violations = self.dyn_compatibility_violations(trait_pred.def_id());
131 if !violations.is_empty() {
132 let reported = report_dyn_incompatibility(
133 tcx,
134 span,
135 Some(hir_id),
136 trait_pred.def_id(),
137 &violations,
138 )
139 .emit();
140 return Ty::new_error(tcx, reported);
141 }
142 }
143 }
144
145 let mut projection_bounds = FxIndexMap::default();
155 for (proj, proj_span) in elaborated_projection_bounds {
156 let item_def_id = proj.item_def_id();
157
158 let proj = proj.map_bound(|mut proj| {
159 let references_self = proj.term.walk().any(|arg| arg == dummy_self.into());
160 if references_self {
161 let guar = self.dcx().emit_err(DynTraitAssocItemBindingMentionsSelf {
162 span,
163 kind: tcx.def_descr(item_def_id),
164 binding: proj_span,
165 });
166 proj.term = replace_dummy_self_with_error(tcx, proj.term, guar);
167 }
168 proj
169 });
170
171 let key = (
172 item_def_id,
173 tcx.anonymize_bound_vars(
174 proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
175 ),
176 );
177 if let Some((old_proj, old_proj_span)) =
178 projection_bounds.insert(key, (proj, proj_span))
179 && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
180 {
181 let kind = tcx.def_descr(item_def_id);
182 let name = tcx.item_name(item_def_id);
183 self.dcx()
184 .struct_span_err(span, format!("conflicting {kind} bindings for `{name}`"))
185 .with_span_label(
186 old_proj_span,
187 format!("`{name}` is specified to be `{}` here", old_proj.term()),
188 )
189 .with_span_label(
190 proj_span,
191 format!("`{name}` is specified to be `{}` here", proj.term()),
192 )
193 .emit();
194 }
195 }
196
197 let principal_trait = regular_traits.into_iter().next();
198
199 let mut ordered_associated_items = vec![];
205
206 if let Some((principal_trait, ref spans)) = principal_trait {
207 let principal_trait = principal_trait.map_bound(|trait_pred| {
208 assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
209 trait_pred.trait_ref
210 });
211
212 for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
213 tcx,
214 [ClauseWithSupertraitSpan::new(
215 ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
216 *spans.last().unwrap(),
217 )],
218 )
219 .filter_only_self()
220 {
221 let clause = clause.instantiate_supertrait(tcx, principal_trait);
222 debug!("observing object predicate `{clause:?}`");
223
224 let bound_predicate = clause.kind();
225 match bound_predicate.skip_binder() {
226 ty::ClauseKind::Trait(pred) => {
227 let trait_ref =
229 tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
230 ordered_associated_items.extend(
231 tcx.associated_items(pred.trait_ref.def_id)
232 .in_definition_order()
233 .filter(|item| item.is_type() || item.is_const())
235 .filter(|item| !item.is_impl_trait_in_trait())
237 .map(|item| (item.def_id, trait_ref)),
238 );
239 }
240 ty::ClauseKind::Projection(pred) => {
241 let pred = bound_predicate.rebind(pred);
242 let references_self =
245 pred.skip_binder().term.walk().any(|arg| arg == dummy_self.into());
246
247 if !references_self {
265 let key = (
266 pred.item_def_id(),
267 tcx.anonymize_bound_vars(
268 pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
269 ),
270 );
271 if !projection_bounds.contains_key(&key) {
272 projection_bounds.insert(key, (pred, supertrait_span));
273 }
274 }
275
276 self.check_elaborated_projection_mentions_input_lifetimes(
277 pred,
278 *spans.first().unwrap(),
279 supertrait_span,
280 );
281 }
282 _ => (),
283 }
284 }
285 }
286
287 for &(projection_bound, span) in projection_bounds.values() {
289 let def_id = projection_bound.item_def_id();
290 if tcx.generics_require_sized_self(def_id) {
291 tcx.emit_node_span_lint(
295 UNUSED_ASSOCIATED_TYPE_BOUNDS,
296 hir_id,
297 span,
298 crate::errors::UnusedAssociatedTypeBounds { span },
299 );
300 }
301 }
302
303 let mut missing_assoc_items = FxIndexSet::default();
315 let projection_bounds: Vec<_> = ordered_associated_items
316 .into_iter()
317 .filter_map(|key @ (def_id, _)| {
318 if let Some(&assoc) = projection_bounds.get(&key) {
319 return Some(assoc);
320 }
321 if !tcx.generics_require_sized_self(def_id) {
322 missing_assoc_items.insert(key);
323 }
324 None
325 })
326 .collect();
327
328 if let Err(guar) = self.check_for_required_assoc_items(
330 principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
331 missing_assoc_items,
332 potential_assoc_items,
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_generic_params = Vec::new();
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_generic_params.push((param.name, param.kind.clone()));
371 param.to_error(tcx)
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_generic_params(
383 missing_generic_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 RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi())
455 } else {
456 RegionInferReason::ExplicitObjectLifetime
457 };
458 self.re_infer(span, reason)
459 }
460 })
461 };
462 debug!(?region_bound);
463
464 Ty::new_dynamic(tcx, existential_predicates, region_bound)
465 }
466
467 fn check_elaborated_projection_mentions_input_lifetimes(
472 &self,
473 pred: ty::PolyProjectionPredicate<'tcx>,
474 span: Span,
475 supertrait_span: Span,
476 ) {
477 let tcx = self.tcx();
478
479 let late_bound_in_projection_term =
487 tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
488 let late_bound_in_term =
489 tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
490 {
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:490",
"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(490u32),
::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);
491 {
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:491",
"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(491u32),
::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);
492
493 self.validate_late_bound_regions(
498 late_bound_in_projection_term,
499 late_bound_in_term,
500 |br_name| {
501 let item_name = tcx.item_name(pred.item_def_id());
502 {
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!(
503 self.dcx(),
504 span,
505 E0582,
506 "binding for associated type `{}` references {}, \
507 which does not appear in the trait input types",
508 item_name,
509 br_name
510 )
511 .with_span_label(supertrait_span, "due to this supertrait")
512 },
513 );
514 }
515
516 fn prohibit_or_lint_bare_trait_object_ty(
521 &self,
522 span: Span,
523 hir_id: hir::HirId,
524 hir_bounds: &[hir::PolyTraitRef<'tcx>],
525 ) -> Option<ErrorGuaranteed> {
526 let tcx = self.tcx();
527 let [poly_trait_ref, ..] = hir_bounds else { return None };
528
529 let in_path = match tcx.parent_hir_node(hir_id) {
530 hir::Node::Ty(hir::Ty {
531 kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
532 ..
533 })
534 | hir::Node::Expr(hir::Expr {
535 kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
536 ..
537 })
538 | hir::Node::PatExpr(hir::PatExpr {
539 kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
540 ..
541 }) if qself.hir_id == hir_id => true,
542 _ => false,
543 };
544 let needs_bracket = in_path
545 && !tcx
546 .sess
547 .source_map()
548 .span_to_prev_source(span)
549 .ok()
550 .is_some_and(|s| s.trim_end().ends_with('<'));
551
552 let is_global = poly_trait_ref.trait_ref.path.is_global();
553
554 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![(
555 span.shrink_to_lo(),
556 format!(
557 "{}dyn {}",
558 if needs_bracket { "<" } else { "" },
559 if is_global { "(" } else { "" },
560 ),
561 )];
562
563 if is_global || needs_bracket {
564 sugg.push((
565 span.shrink_to_hi(),
566 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" }))
})format!(
567 "{}{}",
568 if is_global { ")" } else { "" },
569 if needs_bracket { ">" } else { "" },
570 ),
571 ));
572 }
573
574 if span.edition().at_least_rust_2021() {
575 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!(
576 self.dcx(),
577 span,
578 E0782,
579 "{}",
580 "expected a type, found a trait"
581 );
582 if span.can_be_used_for_suggestions()
583 && poly_trait_ref.trait_ref.trait_def_id().is_some()
584 && !self.maybe_suggest_impl_trait(span, hir_id, hir_bounds, &mut diag)
585 && !self.maybe_suggest_dyn_trait(hir_id, span, sugg, &mut diag)
586 {
587 self.maybe_suggest_add_generic_impl_trait(span, hir_id, &mut diag);
588 }
589 self.maybe_suggest_blanket_trait_impl(span, hir_id, &mut diag);
591 self.maybe_suggest_assoc_ty_bound(hir_id, &mut diag);
592 self.maybe_suggest_typoed_method(
593 hir_id,
594 poly_trait_ref.trait_ref.trait_def_id(),
595 &mut diag,
596 );
597 if let Some(mut sugg) =
600 self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion)
601 && let Suggestions::Enabled(ref mut s1) = diag.suggestions
602 && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
603 {
604 s1.append(s2);
605 sugg.cancel();
606 }
607 Some(diag.emit())
608 } else {
609 tcx.node_span_lint(BARE_TRAIT_OBJECTS, hir_id, span, |lint| {
610 lint.primary_message("trait objects without an explicit `dyn` are deprecated");
611 if span.can_be_used_for_suggestions() {
612 lint.multipart_suggestion(
613 "if this is a dyn-compatible trait, use `dyn`",
614 sugg,
615 Applicability::MachineApplicable,
616 );
617 }
618 self.maybe_suggest_blanket_trait_impl(span, hir_id, lint);
619 });
620 None
621 }
622 }
623
624 fn maybe_suggest_add_generic_impl_trait(
627 &self,
628 span: Span,
629 hir_id: hir::HirId,
630 diag: &mut Diag<'_>,
631 ) -> bool {
632 let tcx = self.tcx();
633
634 let parent_hir_id = tcx.parent_hir_id(hir_id);
635 let parent_item = tcx.hir_get_parent_item(hir_id).def_id;
636
637 let generics = match tcx.hir_node_by_def_id(parent_item) {
638 hir::Node::Item(hir::Item {
639 kind: hir::ItemKind::Struct(_, generics, variant),
640 ..
641 }) => {
642 if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
643 return false;
644 }
645 generics
646 }
647 hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
648 if !def
649 .variants
650 .iter()
651 .flat_map(|variant| variant.data.fields().iter())
652 .any(|field| field.hir_id == parent_hir_id)
653 {
654 return false;
655 }
656 generics
657 }
658 _ => return false,
659 };
660
661 let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(span) else {
662 return false;
663 };
664
665 let param = "TUV"
666 .chars()
667 .map(|c| c.to_string())
668 .chain((0..).map(|i| ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("P{0}", i)) })format!("P{i}")))
669 .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
670 .expect("we definitely can find at least one param name to generate");
671 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())];
672 if let Some(insertion_span) = generics.span_for_param_suggestion() {
673 sugg.push((insertion_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", {1}: {0}", rendered_ty, param))
})format!(", {param}: {}", rendered_ty)));
674 } else {
675 sugg.push((generics.where_clause_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{1}: {0}>", rendered_ty, param))
})format!("<{param}: {}>", rendered_ty)));
676 }
677 diag.multipart_suggestion(
678 "you might be missing a type parameter",
679 sugg,
680 Applicability::MachineApplicable,
681 );
682 true
683 }
684
685 fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
687 &self,
688 span: Span,
689 hir_id: hir::HirId,
690 diag: &mut Diag<'_, G>,
691 ) {
692 let tcx = self.tcx();
693 let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
694 if let hir::Node::Item(hir::Item {
695 kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
696 ..
697 }) = tcx.hir_node_by_def_id(parent_id)
698 && hir_id == impl_self_ty.hir_id
699 {
700 let Some(of_trait) = of_trait else {
701 diag.span_suggestion_verbose(
702 impl_self_ty.span.shrink_to_hi(),
703 "you might have intended to implement this trait for a given type",
704 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" for /* Type */"))
})format!(" for /* Type */"),
705 Applicability::HasPlaceholders,
706 );
707 return;
708 };
709 if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
710 return;
711 }
712 let of_trait_span = of_trait.trait_ref.path.span;
713 let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
715 return;
716 };
717
718 let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(span) else {
719 return;
720 };
721 let sugg = self.add_generic_param_suggestion(generics, span, &impl_trait_name);
722 diag.multipart_suggestion(
723 ::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!(
724 "alternatively use a blanket implementation to implement `{of_trait_name}` for \
725 all types that also implement `{impl_trait_name}`"
726 ),
727 sugg,
728 Applicability::MaybeIncorrect,
729 );
730 }
731 }
732
733 fn maybe_suggest_dyn_trait(
741 &self,
742 hir_id: hir::HirId,
743 span: Span,
744 sugg: Vec<(Span, String)>,
745 diag: &mut Diag<'_>,
746 ) -> bool {
747 let tcx = self.tcx();
748 if span.in_derive_expansion() {
749 return false;
750 }
751
752 match tcx.parent_hir_node(hir_id) {
755 hir::Node::Ty(_)
761 | hir::Node::Expr(_)
762 | hir::Node::PatExpr(_)
763 | hir::Node::PathSegment(_)
764 | hir::Node::AssocItemConstraint(_)
765 | hir::Node::TraitRef(_)
766 | hir::Node::Item(_)
767 | hir::Node::WherePredicate(_) => {}
768
769 hir::Node::Field(field) => {
770 if let hir::Node::Item(hir::Item {
772 kind: hir::ItemKind::Struct(_, _, variant), ..
773 }) = tcx.parent_hir_node(field.hir_id)
774 && variant
775 .fields()
776 .last()
777 .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
778 {
779 } else {
781 return false;
782 }
783 }
784 _ => return false,
785 }
786
787 diag.multipart_suggestion(
789 "you can add the `dyn` keyword if you want a trait object",
790 sugg,
791 Applicability::MachineApplicable,
792 );
793 true
794 }
795
796 fn add_generic_param_suggestion(
797 &self,
798 generics: &hir::Generics<'_>,
799 self_ty_span: Span,
800 impl_trait_name: &str,
801 ) -> Vec<(Span, String)> {
802 let param_name = generics.params.next_type_param_name(None);
804
805 let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
806 (span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", {0}: {1}", param_name,
impl_trait_name))
})format!(", {param_name}: {impl_trait_name}"))
807 } else {
808 (generics.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}: {1}>", param_name,
impl_trait_name))
})format!("<{param_name}: {impl_trait_name}>"))
809 };
810 ::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]
811 }
812
813 fn maybe_suggest_impl_trait(
815 &self,
816 span: Span,
817 hir_id: hir::HirId,
818 hir_bounds: &[hir::PolyTraitRef<'tcx>],
819 diag: &mut Diag<'_>,
820 ) -> bool {
821 let tcx = self.tcx();
822 let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
823 let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
830 hir::Node::Item(hir::Item {
831 kind: hir::ItemKind::Fn { sig, generics, .. }, ..
832 }) => (sig, generics),
833 hir::Node::TraitItem(hir::TraitItem {
834 kind: hir::TraitItemKind::Fn(sig, _),
835 generics,
836 ..
837 }) => (sig, generics),
838 hir::Node::ImplItem(hir::ImplItem {
839 kind: hir::ImplItemKind::Fn(sig, _),
840 generics,
841 ..
842 }) => (sig, generics),
843 _ => return false,
844 };
845 let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(span) else {
846 return false;
847 };
848 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())];
849 let is_dyn_compatible = hir_bounds.iter().all(|bound| match bound.trait_ref.path.res {
851 Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
852 _ => false,
853 });
854
855 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!(
856 tcx.parent_hir_node(hir_id),
857 hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
858 );
859
860 if let hir::FnRetTy::Return(ty) = sig.decl.output
862 && ty.peel_refs().hir_id == hir_id
863 {
864 let pre = if !is_dyn_compatible {
865 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is dyn-incompatible, ",
trait_name))
})format!("`{trait_name}` is dyn-incompatible, ")
866 } else {
867 String::new()
868 };
869 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!(
870 "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
871 single underlying type",
872 );
873
874 diag.multipart_suggestion(msg, impl_sugg, Applicability::MachineApplicable);
875
876 if is_dyn_compatible {
878 let suggestion = if borrowed {
882 ::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}>"))]
883 } else {
884 ::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![
885 (ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
886 (ty.span.shrink_to_hi(), ">".to_string()),
887 ]
888 };
889
890 diag.multipart_suggestion(
891 "alternatively, you can return an owned trait object",
892 suggestion,
893 Applicability::MachineApplicable,
894 );
895 }
896 return true;
897 }
898
899 for ty in sig.decl.inputs {
901 if ty.peel_refs().hir_id != hir_id {
902 continue;
903 }
904 let sugg = self.add_generic_param_suggestion(generics, span, &trait_name);
905 diag.multipart_suggestion(
906 ::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}`"),
907 sugg,
908 Applicability::MachineApplicable,
909 );
910 diag.multipart_suggestion(
911 "you can also use an opaque type, but users won't be able to specify the type \
912 parameter when calling the `fn`, having to rely exclusively on type inference",
913 impl_sugg,
914 Applicability::MachineApplicable,
915 );
916 if !is_dyn_compatible {
917 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!(
918 "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
919 ));
920 } else {
921 let (dyn_str, paren_dyn_str) =
923 if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
924
925 let sugg = if let [_, _, ..] = hir_bounds {
926 ::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![
928 (span.shrink_to_lo(), paren_dyn_str.to_string()),
929 (span.shrink_to_hi(), ")".to_string()),
930 ]
931 } else {
932 ::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())]
933 };
934 diag.multipart_suggestion(
935 ::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!(
936 "alternatively, use a trait object to accept any type that implements \
937 `{trait_name}`, accessing its methods at runtime using dynamic dispatch",
938 ),
939 sugg,
940 Applicability::MachineApplicable,
941 );
942 }
943 return true;
944 }
945 false
946 }
947
948 fn maybe_suggest_assoc_ty_bound(&self, hir_id: hir::HirId, diag: &mut Diag<'_>) {
949 let mut parents = self.tcx().hir_parent_iter(hir_id);
950
951 if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
952 && let Some(obj_ty) = constraint.ty()
953 && let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
954 {
955 if let Some((_, hir::Node::Ty(ty))) = parents.next()
956 && let hir::TyKind::TraitObject(..) = ty.kind
957 {
958 return;
960 }
961
962 if trait_ref
963 .path
964 .segments
965 .iter()
966 .find_map(|seg| {
967 seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
968 })
969 .is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
970 {
971 return;
973 }
974
975 let lo = if constraint.gen_args.span_ext.is_dummy() {
976 constraint.ident.span
977 } else {
978 constraint.gen_args.span_ext
979 };
980 let hi = obj_ty.span;
981
982 if !lo.eq_ctxt(hi) {
983 return;
984 }
985
986 diag.span_suggestion_verbose(
987 lo.between(hi),
988 "you might have meant to write a bound here",
989 ": ",
990 Applicability::MaybeIncorrect,
991 );
992 }
993 }
994
995 fn maybe_suggest_typoed_method(
996 &self,
997 hir_id: hir::HirId,
998 trait_def_id: Option<DefId>,
999 diag: &mut Diag<'_>,
1000 ) {
1001 let tcx = self.tcx();
1002 let Some(trait_def_id) = trait_def_id else {
1003 return;
1004 };
1005 let hir::Node::Expr(hir::Expr {
1006 kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
1007 ..
1008 }) = tcx.parent_hir_node(hir_id)
1009 else {
1010 return;
1011 };
1012 if path_ty.hir_id != hir_id {
1013 return;
1014 }
1015 let names: Vec<_> = tcx
1016 .associated_items(trait_def_id)
1017 .in_definition_order()
1018 .filter(|assoc| assoc.namespace() == hir::def::Namespace::ValueNS)
1019 .map(|cand| cand.name())
1020 .collect();
1021 if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
1022 diag.span_suggestion_verbose(
1023 segment.ident.span,
1024 ::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!(
1025 "you may have misspelled this associated item, causing `{}` \
1026 to be interpreted as a type rather than a trait",
1027 tcx.item_name(trait_def_id),
1028 ),
1029 typo,
1030 Applicability::MaybeIncorrect,
1031 );
1032 }
1033 }
1034}
1035
1036fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
1037 tcx: TyCtxt<'tcx>,
1038 t: T,
1039 guar: ErrorGuaranteed,
1040) -> T {
1041 t.fold_with(&mut BottomUpFolder {
1042 tcx,
1043 ty_op: |ty| {
1044 if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
1045 },
1046 lt_op: |lt| lt,
1047 ct_op: |ct| ct,
1048 })
1049}