1pub mod ambiguity;
2pub mod call_kind;
3pub mod fulfillment_errors;
4pub mod on_unimplemented;
5mod overflow;
6pub mod suggestions;
7
8use std::{fmt, iter};
9
10use rustc_crate_store::{ExternCrate, ExternCrateSource};
11use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
12use rustc_data_structures::unord::UnordSet;
13use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
14use rustc_hir::attrs::lang_items::LangItem;
15use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
16use rustc_hir::intravisit::Visitor;
17use rustc_hir::{self as hir, AmbigArg};
18use rustc_infer::traits::solve::Goal;
19use rustc_infer::traits::{
20 DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
21 PredicateObligation, SelectionError,
22};
23use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
24use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
25use rustc_next_trait_solver::solve::TyOrConstInferVar;
26use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span};
27use thin_vec::ThinVec;
28use tracing::{info, instrument};
29
30pub use self::overflow::*;
31use crate::error_reporting::TypeErrCtxt;
32use crate::traits::{FulfillmentError, FulfillmentErrorCode};
33
34#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CandidateSimilarity {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
CandidateSimilarity::Exact { ignoring_lifetimes: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Exact",
"ignoring_lifetimes", &__self_0),
CandidateSimilarity::Fuzzy { ignoring_lifetimes: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Fuzzy",
"ignoring_lifetimes", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for CandidateSimilarity { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CandidateSimilarity { }
#[automatically_derived]
impl ::core::clone::Clone for CandidateSimilarity {
#[inline]
fn clone(&self) -> CandidateSimilarity {
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for CandidateSimilarity { }
#[automatically_derived]
impl ::core::cmp::PartialEq for CandidateSimilarity {
#[inline]
fn eq(&self, other: &CandidateSimilarity) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(CandidateSimilarity::Exact { ignoring_lifetimes: __self_0 },
CandidateSimilarity::Exact { ignoring_lifetimes: __arg1_0 })
=> __self_0 == __arg1_0,
(CandidateSimilarity::Fuzzy { ignoring_lifetimes: __self_0 },
CandidateSimilarity::Fuzzy { ignoring_lifetimes: __arg1_0 })
=> __self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CandidateSimilarity {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for CandidateSimilarity {
#[inline]
fn partial_cmp(&self, other: &CandidateSimilarity)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for CandidateSimilarity {
#[inline]
fn cmp(&self, other: &CandidateSimilarity) -> ::core::cmp::Ordering {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
::core::cmp::Ordering::Equal =>
match (self, other) {
(CandidateSimilarity::Exact { ignoring_lifetimes: __self_0
}, CandidateSimilarity::Exact { ignoring_lifetimes: __arg1_0
}) => ::core::cmp::Ord::cmp(__self_0, __arg1_0),
(CandidateSimilarity::Fuzzy { ignoring_lifetimes: __self_0
}, CandidateSimilarity::Fuzzy { ignoring_lifetimes: __arg1_0
}) => ::core::cmp::Ord::cmp(__self_0, __arg1_0),
_ => unsafe { ::core::intrinsics::unreachable() }
},
cmp => cmp,
}
}
}Ord)]
39pub enum CandidateSimilarity {
40 Exact { ignoring_lifetimes: bool },
41 Fuzzy { ignoring_lifetimes: bool },
42}
43
44#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ImplCandidate<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "ImplCandidate",
"trait_ref", &self.trait_ref, "similarity", &self.similarity,
"impl_def_id", &&self.impl_def_id)
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for ImplCandidate<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::clone::Clone for ImplCandidate<'tcx> {
#[inline]
fn clone(&self) -> ImplCandidate<'tcx> {
let _: ::core::clone::AssertParamIsClone<ty::TraitRef<'tcx>>;
let _: ::core::clone::AssertParamIsClone<CandidateSimilarity>;
let _: ::core::clone::AssertParamIsClone<DefId>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for ImplCandidate<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for ImplCandidate<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for ImplCandidate<'tcx> {
#[inline]
fn eq(&self, other: &ImplCandidate<'tcx>) -> bool {
self.trait_ref == other.trait_ref &&
self.similarity == other.similarity &&
self.impl_def_id == other.impl_def_id
}
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for ImplCandidate<'tcx> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<ty::TraitRef<'tcx>>;
let _: ::core::cmp::AssertParamIsEq<CandidateSimilarity>;
let _: ::core::cmp::AssertParamIsEq<DefId>;
}
}Eq)]
45pub struct ImplCandidate<'tcx> {
46 pub trait_ref: ty::TraitRef<'tcx>,
47 pub similarity: CandidateSimilarity,
48 impl_def_id: DefId,
49}
50
51enum GetSafeTransmuteErrorAndReason {
52 Silent,
53 Default,
54 Error { err_msg: String, safe_transmute_explanation: Option<String> },
55}
56
57pub struct FindExprBySpan<'hir> {
59 pub span: Span,
60 pub result: Option<&'hir hir::Expr<'hir>>,
61 pub ty_result: Option<&'hir hir::Ty<'hir>>,
62 pub include_closures: bool,
63 pub tcx: TyCtxt<'hir>,
64}
65
66impl<'hir> FindExprBySpan<'hir> {
67 pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
68 Self { span, result: None, ty_result: None, tcx, include_closures: false }
69 }
70}
71
72impl<'v> Visitor<'v> for FindExprBySpan<'v> {
73 type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
74
75 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
76 self.tcx
77 }
78
79 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
80 if self.span == ex.span {
81 self.result = Some(ex);
82 } else {
83 if let hir::ExprKind::Closure(..) = ex.kind
84 && self.include_closures
85 && let closure_header_sp = self.span.with_hi(ex.span.hi())
86 && closure_header_sp == ex.span
87 {
88 self.result = Some(ex);
89 }
90 hir::intravisit::walk_expr(self, ex);
91 }
92 }
93
94 fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
95 if self.span == ty.span {
96 self.ty_result = Some(ty.as_unambig_ty());
97 } else {
98 hir::intravisit::walk_ty(self, ty);
99 }
100 }
101}
102
103#[derive(#[automatically_derived]
impl ::core::clone::Clone for ArgKind {
#[inline]
fn clone(&self) -> ArgKind {
match self {
ArgKind::Arg(__self_0, __self_1) =>
ArgKind::Arg(::core::clone::Clone::clone(__self_0),
::core::clone::Clone::clone(__self_1)),
ArgKind::Tuple(__self_0, __self_1) =>
ArgKind::Tuple(::core::clone::Clone::clone(__self_0),
::core::clone::Clone::clone(__self_1)),
}
}
}Clone)]
105pub enum ArgKind {
106 Arg(String, String),
108
109 Tuple(Option<Span>, Vec<(String, String)>),
114}
115
116impl ArgKind {
117 fn empty() -> ArgKind {
118 ArgKind::Arg("_".to_owned(), "_".to_owned())
119 }
120
121 pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
124 match t.kind() {
125 ty::Tuple(tys) => ArgKind::Tuple(
126 span,
127 tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
128 ),
129 _ => ArgKind::Arg("_".to_owned(), t.to_string()),
130 }
131 }
132}
133
134#[derive(#[automatically_derived]
impl ::core::marker::Copy for DefIdOrName { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DefIdOrName { }
#[automatically_derived]
impl ::core::clone::Clone for DefIdOrName {
#[inline]
fn clone(&self) -> DefIdOrName {
let _: ::core::clone::AssertParamIsClone<DefId>;
let _: ::core::clone::AssertParamIsClone<&'static str>;
*self
}
}Clone)]
135pub enum DefIdOrName {
136 DefId(DefId),
137 Name(&'static str),
138}
139
140impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
141 pub fn report_fulfillment_errors(
142 &self,
143 mut errors: ThinVec<FulfillmentError<'tcx>>,
144 ) -> ErrorGuaranteed {
145 #[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ErrorDescriptor<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"ErrorDescriptor", "goal", &self.goal, "index", &&self.index)
}
}Debug)]
146 struct ErrorDescriptor<'tcx> {
147 goal: Goal<'tcx, ty::Predicate<'tcx>>,
148 index: Option<usize>, }
150
151 let mut error_map: FxIndexMap<_, Vec<_>> = self
152 .reported_trait_errors
153 .borrow()
154 .iter()
155 .map(|(&span, goals)| {
156 (span, goals.0.iter().map(|&goal| ErrorDescriptor { goal, index: None }).collect())
157 })
158 .collect();
159
160 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for ErrorSortKey {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ErrorSortKey::SubtypeFormat(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"SubtypeFormat", __self_0, &__self_1),
ErrorSortKey::OtherKind =>
::core::fmt::Formatter::write_str(f, "OtherKind"),
ErrorSortKey::SizedTrait =>
::core::fmt::Formatter::write_str(f, "SizedTrait"),
ErrorSortKey::MetaSizedTrait =>
::core::fmt::Formatter::write_str(f, "MetaSizedTrait"),
ErrorSortKey::PointeeSizedTrait =>
::core::fmt::Formatter::write_str(f, "PointeeSizedTrait"),
ErrorSortKey::Coerce =>
::core::fmt::Formatter::write_str(f, "Coerce"),
ErrorSortKey::WellFormed =>
::core::fmt::Formatter::write_str(f, "WellFormed"),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ErrorSortKey { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ErrorSortKey {
#[inline]
fn eq(&self, other: &ErrorSortKey) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(ErrorSortKey::SubtypeFormat(__self_0, __self_1),
ErrorSortKey::SubtypeFormat(__arg1_0, __arg1_1)) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ErrorSortKey {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<usize>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for ErrorSortKey {
#[inline]
fn partial_cmp(&self, other: &ErrorSortKey)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for ErrorSortKey {
#[inline]
fn cmp(&self, other: &ErrorSortKey) -> ::core::cmp::Ordering {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
::core::cmp::Ordering::Equal =>
match (self, other) {
(ErrorSortKey::SubtypeFormat(__self_0, __self_1),
ErrorSortKey::SubtypeFormat(__arg1_0, __arg1_1)) =>
match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(__self_1, __arg1_1),
cmp => cmp,
},
_ => ::core::cmp::Ordering::Equal,
},
cmp => cmp,
}
}
}Ord)]
165 enum ErrorSortKey {
166 SubtypeFormat(usize, usize),
167 OtherKind,
168 SizedTrait,
169 MetaSizedTrait,
170 PointeeSizedTrait,
171 Coerce,
172 WellFormed,
173 }
174 errors.sort_by_key(|e| {
175 let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() {
176 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()),
177 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => Some(pred.def_id()),
178 _ => None,
179 };
180
181 match e.obligation.predicate.kind().skip_binder() {
182 ty::PredicateKind::Subtype(_)
183 if #[allow(non_exhaustive_omitted_patterns)] match e.obligation.cause.span.desugaring_kind()
{
Some(DesugaringKind::FormatLiteral { .. }) => true,
_ => false,
}matches!(
184 e.obligation.cause.span.desugaring_kind(),
185 Some(DesugaringKind::FormatLiteral { .. })
186 ) =>
187 {
188 let (_, row, col, ..) =
189 self.tcx.sess.source_map().span_to_location_info(e.obligation.cause.span);
190 ErrorSortKey::SubtypeFormat(row, col)
191 }
192 _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => {
193 ErrorSortKey::SizedTrait
194 }
195 _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => {
196 ErrorSortKey::MetaSizedTrait
197 }
198 _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => {
199 ErrorSortKey::PointeeSizedTrait
200 }
201 ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce,
202 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
203 ErrorSortKey::WellFormed
204 }
205 _ => ErrorSortKey::OtherKind,
206 }
207 });
208
209 for (index, error) in errors.iter().enumerate() {
210 let mut span = error.obligation.cause.span;
213 let expn_data = span.ctxt().outer_expn_data();
214 if let ExpnKind::Desugaring(_) = expn_data.kind {
215 span = expn_data.call_site;
216 }
217
218 error_map
219 .entry(span)
220 .or_default()
221 .push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
222 }
223
224 let mut is_suppressed = ::alloc::vec::from_elem(false, errors.len())vec![false; errors.len()];
227 let covered_by_trait_error =
232 |cond: &ErrorDescriptor<'tcx>, error: &ErrorDescriptor<'tcx>| {
233 let is_definite = |error: &ErrorDescriptor<'tcx>| {
234 error.index.is_some_and(|index| {
235 !#[allow(non_exhaustive_omitted_patterns)] match errors[index].code {
FulfillmentErrorCode::Ambiguity { .. } => true,
_ => false,
}matches!(errors[index].code, FulfillmentErrorCode::Ambiguity { .. })
236 })
237 };
238 is_definite(cond)
239 && is_definite(error)
240 && self.trait_error_implies_projection_error(cond.goal, error.goal)
241 };
242 for (_, error_set) in error_map.iter() {
243 for error in error_set {
245 if let Some(index) = error.index {
246 for error2 in error_set {
250 if error2.index.is_some_and(|index2| is_suppressed[index2]) {
251 continue;
255 }
256
257 if (self.error_implies(error2.goal, error.goal)
258 && !(error2.index >= error.index
259 && self.error_implies(error.goal, error2.goal)))
260 || covered_by_trait_error(error2, error)
261 {
262 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs:262",
"rustc_trait_selection::error_reporting::traits",
::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs"),
::tracing_core::__macro_support::Option::Some(262u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::INFO <=
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("skipping {0:?} (implied by {1:?})",
error, error2) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("skipping {:?} (implied by {:?})", error, error2);
263 is_suppressed[index] = true;
264 break;
265 }
266 }
267 }
268 }
269 }
270
271 let ambiguity_infer_var = |error: &FulfillmentError<'tcx>| match error.code {
282 FulfillmentErrorCode::Ambiguity { overflow: None } => self
283 .ambiguity_term(self.resolve_vars_if_possible(error.obligation.predicate))
284 .and_then(|term| {
285 ty::GenericArg::from(term)
286 .walk()
287 .find_map(TyOrConstInferVar::maybe_from_generic_arg::<TyCtxt<'tcx>>)
288 })
289 .map(|var| match var {
290 TyOrConstInferVar::Ty(vid) => {
291 TyOrConstInferVar::Ty(self.sub_unification_table_root_var(vid))
292 }
293 other => other,
294 }),
295 _ => None,
296 };
297 let infer_vars: Vec<_> = errors.iter().map(ambiguity_infer_var).collect();
298
299 let mut reported = None;
300 let mut merged = ::alloc::vec::from_elem(None, errors.len())vec![None; errors.len()];
301 let mut reported_as_primary = ::alloc::vec::from_elem(false, errors.len())vec![false; errors.len()];
302 for from_expansion in [false, true] {
303 for (index, (error, suppressed)) in iter::zip(&errors, &is_suppressed).enumerate() {
304 if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
305 if !error.references_error() {
306 let guar = if let Some(guar) = merged[index] {
307 guar
308 } else {
309 let group: Vec<usize> = match infer_vars[index] {
310 Some(var) => (0..errors.len())
311 .filter(|&other| {
312 other != index && infer_vars[other] == Some(var)
313 })
314 .collect(),
315 None => ::alloc::vec::Vec::new()vec![],
316 };
317 let merges = |other: usize| {
323 errors[other].obligation.cause.span == error.obligation.cause.span
324 && match errors[other].obligation.predicate.kind().skip_binder()
325 {
326 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
327 !#[allow(non_exhaustive_omitted_patterns)] match self.tcx.as_lang_item(data.def_id())
{
Some(LangItem::Sized | LangItem::MetaSized | LangItem::PointeeSized) =>
true,
_ => false,
}matches!(
328 self.tcx.as_lang_item(data.def_id()),
329 Some(
330 LangItem::Sized
331 | LangItem::MetaSized
332 | LangItem::PointeeSized
333 )
334 )
335 }
336 ty::PredicateKind::Clause(ty::ClauseKind::Projection(
337 _,
338 )) => true,
339 _ => false,
340 }
341 };
342 let related: Vec<_> = group
343 .iter()
344 .filter(|&&other| {
345 merges(other)
349 && !is_suppressed[other]
350 && !errors[other].references_error()
351 && !reported_as_primary[other]
352 })
353 .map(|&other| &errors[other])
354 .collect();
355 let guar = self.report_fulfillment_error(error, &related);
356 for &other in &group {
357 if merges(other) {
358 merged[other] = Some(guar);
359 }
360 }
361 reported_as_primary[index] = true;
362 guar
363 };
364 self.infcx.set_tainted_by_errors(guar);
365 reported = Some(guar);
366 let mut span = error.obligation.cause.span;
369 let expn_data = span.ctxt().outer_expn_data();
370 if let ExpnKind::Desugaring(_) = expn_data.kind {
371 span = expn_data.call_site;
372 }
373 self.reported_trait_errors
374 .borrow_mut()
375 .entry(span)
376 .or_insert_with(|| (::alloc::vec::Vec::new()vec![], guar))
377 .0
378 .push(error.obligation.as_goal());
379 }
380 if let Some(guar) = self.dcx().has_errors() {
381 self.infcx.set_tainted_by_errors(guar);
382 }
383 }
384 }
385 }
386
387 reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
391 }
392
393 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("report_fulfillment_error",
"rustc_trait_selection::error_reporting::traits",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs"),
::tracing_core::__macro_support::Option::Some(393u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("error")
}> =
::tracing::__macro_support::FieldName::new("error");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("related")
}> =
::tracing::__macro_support::FieldName::new("related");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&error)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&related)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: ErrorGuaranteed = loop {};
return __tracing_attr_fake_return;
}
{
let mut error =
FulfillmentError {
obligation: error.obligation.clone(),
code: error.code.clone(),
root_obligation: error.root_obligation.clone(),
};
if #[allow(non_exhaustive_omitted_patterns)] match error.code {
FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
| FulfillmentErrorCode::Project(_) => true,
_ => false,
} &&
self.apply_do_not_recommend(&mut error.obligation,
&error.root_obligation) {
error.code =
FulfillmentErrorCode::Select(SelectionError::Unimplemented);
}
match error.code {
FulfillmentErrorCode::Select(ref selection_error) =>
self.report_selection_error(error.obligation.clone(),
&error.root_obligation, selection_error),
FulfillmentErrorCode::Project(ref e) => {
self.report_projection_error(&error.obligation, e)
}
FulfillmentErrorCode::Outlives =>
self.dcx().struct_span_err(error.obligation.cause.span,
"higher-ranked lifetime bound could not be satisfied").emit(),
FulfillmentErrorCode::Ambiguity { overflow: None } => {
self.maybe_report_ambiguity(&error.obligation, related)
}
FulfillmentErrorCode::Ambiguity {
overflow: Some(suggest_increasing_limit) } => {
self.report_overflow_no_abort(error.obligation.clone(),
suggest_increasing_limit)
}
FulfillmentErrorCode::Subtype(ref expected_found, ref err) =>
self.report_mismatched_types(&error.obligation.cause,
error.obligation.param_env, expected_found.expected,
expected_found.found, *err).emit(),
FulfillmentErrorCode::ConstEquate(ref expected_found, ref err)
=> {
let mut diag =
self.report_mismatched_consts(&error.obligation.cause,
error.obligation.param_env, expected_found.expected,
expected_found.found, *err);
let code =
error.obligation.cause.code().peel_derives().peel_match_impls();
if let ObligationCauseCode::WhereClause(..) |
ObligationCauseCode::WhereClauseInExpr(..) = code {
self.note_obligation_cause_code(error.obligation.cause.body_def_id,
&mut diag, error.obligation.predicate,
error.obligation.param_env, code,
&mut ::alloc::vec::Vec::new(), &mut Default::default());
}
diag.emit()
}
FulfillmentErrorCode::Cycle(ref cycle) =>
self.report_overflow_obligation_cycle(cycle),
}
}
}
}#[instrument(skip(self), level = "debug")]
394 fn report_fulfillment_error(
395 &self,
396 error: &FulfillmentError<'tcx>,
397 related: &[&FulfillmentError<'tcx>],
398 ) -> ErrorGuaranteed {
399 let mut error = FulfillmentError {
400 obligation: error.obligation.clone(),
401 code: error.code.clone(),
402 root_obligation: error.root_obligation.clone(),
403 };
404 if matches!(
405 error.code,
406 FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
407 | FulfillmentErrorCode::Project(_)
408 ) && self.apply_do_not_recommend(&mut error.obligation, &error.root_obligation)
409 {
410 error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
411 }
412
413 match error.code {
414 FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
415 error.obligation.clone(),
416 &error.root_obligation,
417 selection_error,
418 ),
419 FulfillmentErrorCode::Project(ref e) => {
420 self.report_projection_error(&error.obligation, e)
421 }
422 FulfillmentErrorCode::Outlives => self
423 .dcx()
424 .struct_span_err(
425 error.obligation.cause.span,
426 "higher-ranked lifetime bound could not be satisfied",
427 )
428 .emit(),
429 FulfillmentErrorCode::Ambiguity { overflow: None } => {
430 self.maybe_report_ambiguity(&error.obligation, related)
431 }
432 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
433 self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
434 }
435 FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
436 .report_mismatched_types(
437 &error.obligation.cause,
438 error.obligation.param_env,
439 expected_found.expected,
440 expected_found.found,
441 *err,
442 )
443 .emit(),
444 FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
445 let mut diag = self.report_mismatched_consts(
446 &error.obligation.cause,
447 error.obligation.param_env,
448 expected_found.expected,
449 expected_found.found,
450 *err,
451 );
452 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
453 if let ObligationCauseCode::WhereClause(..)
454 | ObligationCauseCode::WhereClauseInExpr(..) = code
455 {
456 self.note_obligation_cause_code(
457 error.obligation.cause.body_def_id,
458 &mut diag,
459 error.obligation.predicate,
460 error.obligation.param_env,
461 code,
462 &mut vec![],
463 &mut Default::default(),
464 );
465 }
466 diag.emit()
467 }
468 FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
469 }
470 }
471
472 fn extern_crates_with_the_same_name(
476 &self,
477 expected_def_id: DefId,
478 trait_def_id: DefId,
479 ) -> bool {
480 if expected_def_id.is_local() || trait_def_id.is_local() {
481 return false;
482 }
483 match (
487 self.tcx.extern_crate(expected_def_id.krate),
488 self.tcx.extern_crate(trait_def_id.krate),
489 ) {
490 (
491 Some(&ExternCrate {
492 src: ExternCrateSource::Extern(expected_def_id),
493 dependency_of: LOCAL_CRATE,
494 ..
495 }),
496 Some(&ExternCrate {
497 src: ExternCrateSource::Extern(trait_def_id),
498 dependency_of: LOCAL_CRATE,
499 ..
500 }),
501 ) => self.tcx.item_name(expected_def_id) == self.tcx.item_name(trait_def_id),
502 _ => false,
503 }
504 }
505
506 pub fn check_same_definition_different_crate<F>(
507 &self,
508 err: &mut Diag<'_>,
509 expected_did: DefId,
510 found_dids: impl Iterator<Item = DefId>,
511 get_impls: F,
512 ty: &str,
513 ) -> bool
514 where
515 F: Fn(DefId) -> Vec<Span>,
516 {
517 let krate = self.tcx.crate_name(expected_did.krate);
518 let name = self.tcx.item_name(expected_did);
519 let definitions_with_same_path: UnordSet<_> = found_dids
520 .filter(|&def_id| {
521 def_id.krate != expected_did.krate
522 && (self.extern_crates_with_the_same_name(expected_did, def_id)
523 || self.tcx.crate_name(def_id.krate) == krate)
524 && self.tcx.item_name(def_id) == name
525 })
526 .map(|def_id| (self.tcx.def_path_str(def_id), def_id))
527 .collect();
528
529 let definitions_with_same_path =
530 definitions_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
531 let mut suggested = false;
532 let mut trait_is_impl = false;
533
534 if !definitions_with_same_path.is_empty() {
535 let mut span: MultiSpan = self.tcx.def_span(expected_did).into();
536 span.push_span_label(
537 self.tcx.def_span(expected_did),
538 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this is the expected {0}", ty))
})format!("this is the expected {ty}"),
539 );
540 suggested = true;
541 for (_, definition_with_same_path) in &definitions_with_same_path {
542 let definitions_impls = get_impls(*definition_with_same_path);
543 if definitions_impls.is_empty() {
544 continue;
545 }
546
547 for candidate_span in definitions_impls {
548 span.push_span_label(candidate_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this is the found {0}", ty))
})format!("this is the found {ty}"));
549 trait_is_impl = true;
550 }
551 }
552 if !trait_is_impl {
553 for (_, def_id) in definitions_with_same_path {
554 span.push_span_label(
555 self.tcx.def_span(def_id),
556 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this is the {0} that was imported",
ty))
})format!("this is the {ty} that was imported"),
557 );
558 }
559 }
560 self.note_two_crate_versions(expected_did.krate, span, err);
561 err.help("you can use `cargo tree` to explore your dependency tree");
562 }
563 suggested
564 }
565}
566
567pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
570 use std::fmt::Write;
571
572 let trait_ref = tcx.impl_opt_trait_ref(impl_def_id)?.instantiate_identity().skip_norm_wip();
573 let mut w = "impl".to_owned();
574
575 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for SizednessFound {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"SizednessFound", "sized", &self.sized, "meta_sized",
&&self.meta_sized)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for SizednessFound {
#[inline]
fn default() -> SizednessFound {
SizednessFound {
sized: ::core::default::Default::default(),
meta_sized: ::core::default::Default::default(),
}
}
}Default)]
576 struct SizednessFound {
577 sized: bool,
578 meta_sized: bool,
579 }
580
581 let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
582
583 let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
584
585 let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
586 if !arg_names.is_empty() {
587 w.push('<');
588 w.push_str(&arg_names.join(", "));
589 w.push('>');
590
591 for ty in args.types() {
592 types_with_sizedness_bounds.insert(ty, SizednessFound::default());
594 }
595 }
596
597 w.write_fmt(format_args!(" {0}{1} for {2}",
tcx.impl_polarity(impl_def_id).as_str(),
trait_ref.print_only_trait_path(),
tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip()))write!(
598 w,
599 " {}{} for {}",
600 tcx.impl_polarity(impl_def_id).as_str(),
601 trait_ref.print_only_trait_path(),
602 tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip()
603 )
604 .unwrap();
605
606 let clauses = tcx.clauses_of(impl_def_id).clauses;
607 let mut pretty_clauses = Vec::with_capacity(clauses.len());
608
609 let sized_trait = tcx.lang_items().sized_trait();
610 let meta_sized_trait = tcx.lang_items().meta_sized_trait();
611
612 for (c, _) in clauses {
613 if let Some(trait_clause) = c.as_trait_clause() {
615 let self_ty = trait_clause.self_ty().skip_binder();
616 let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
617 if Some(trait_clause.def_id()) == sized_trait {
618 sizedness_of.sized = true;
619 continue;
620 } else if Some(trait_clause.def_id()) == meta_sized_trait {
621 sizedness_of.meta_sized = true;
622 continue;
623 }
624 }
625
626 pretty_clauses.push(c.to_string());
627 }
628
629 for (ty, sizedness) in types_with_sizedness_bounds {
630 if !tcx.features().sized_hierarchy() {
631 if sizedness.sized {
632 } else {
634 pretty_clauses.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ?Sized", ty))
})format!("{ty}: ?Sized"));
635 }
636 } else {
637 if sizedness.sized {
638 pretty_clauses.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: Sized", ty))
})format!("{ty}: Sized"));
640 } else if sizedness.meta_sized {
641 pretty_clauses.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: MetaSized", ty))
})format!("{ty}: MetaSized"));
642 } else {
643 pretty_clauses.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: PointeeSized", ty))
})format!("{ty}: PointeeSized"));
644 }
645 }
646 }
647
648 if !pretty_clauses.is_empty() {
649 w.write_fmt(format_args!("\n where {0}", pretty_clauses.join(", ")))write!(w, "\n where {}", pretty_clauses.join(", ")).unwrap();
650 }
651
652 w.push(';');
653 Some(w)
654}
655
656impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
657 pub fn report_extra_impl_obligation(
658 &self,
659 error_span: Span,
660 impl_item_def_id: LocalDefId,
661 trait_item_def_id: DefId,
662 requirement: &dyn fmt::Display,
663 ) -> Diag<'a> {
664 let mut err = {
self.dcx().struct_span_err(error_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("impl has stricter requirements than trait"))
})).with_code(E0276)
}struct_span_code_err!(
665 self.dcx(),
666 error_span,
667 E0276,
668 "impl has stricter requirements than trait"
669 );
670
671 if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
672 if let Some(span) = self.tcx.hir_span_if_local(trait_item_def_id) {
673 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
674 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("definition of `{0}` from trait",
item_name))
})format!("definition of `{item_name}` from trait"));
675 }
676 }
677
678 err.span_label(error_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("impl has extra requirement {0}",
requirement))
})format!("impl has extra requirement {requirement}"));
679
680 err
681 }
682}
683
684pub fn report_dyn_incompatibility<'tcx>(
685 tcx: TyCtxt<'tcx>,
686 span: Span,
687 hir_id: Option<hir::HirId>,
688 trait_def_id: DefId,
689 violations: &[DynCompatibilityViolation],
690) -> Diag<'tcx> {
691 let trait_str = tcx.def_path_str(trait_def_id);
692 let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
693 hir::Node::Item(item) => match item.kind {
694 hir::ItemKind::Trait { ident, .. } | hir::ItemKind::TraitAlias(_, ident, _, _) => {
695 Some(ident.span)
696 }
697 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
698 },
699 _ => None,
700 });
701
702 let mut err = {
tcx.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the {0} `{1}` is not dyn compatible",
tcx.def_descr(trait_def_id), trait_str))
})).with_code(E0038)
}struct_span_code_err!(
703 tcx.dcx(),
704 span,
705 E0038,
706 "the {} `{}` is not dyn compatible",
707 tcx.def_descr(trait_def_id),
708 trait_str
709 );
710 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is not dyn compatible",
trait_str))
})format!("`{trait_str}` is not dyn compatible"));
711
712 attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
713
714 let mut reported_violations = FxIndexSet::default();
715 let mut multi_span = ::alloc::vec::Vec::new()vec![];
716 let mut messages = ::alloc::vec::Vec::new()vec![];
717 for violation in violations {
718 if let DynCompatibilityViolation::SizedSelf(sp) = &violation
719 && !sp.is_empty()
720 {
721 reported_violations.insert(DynCompatibilityViolation::SizedSelf(::alloc::vec::Vec::new()vec![].into()));
724 }
725 if reported_violations.insert(violation.clone()) {
726 let spans = violation.spans();
727 let msg = if trait_span.is_none() || spans.is_empty() {
728 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the trait is not dyn compatible because {0}",
violation.error_msg()))
})format!("the trait is not dyn compatible because {}", violation.error_msg())
729 } else {
730 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("...because {0}",
violation.error_msg()))
})format!("...because {}", violation.error_msg())
731 };
732 if spans.is_empty() {
733 err.note(msg);
734 } else {
735 for span in spans {
736 multi_span.push(span);
737 messages.push(msg.clone());
738 }
739 }
740 }
741 }
742 let has_multi_span = !multi_span.is_empty();
743 let mut note_span = MultiSpan::from_spans(multi_span.clone());
744 if let (Some(trait_span), true) = (trait_span, has_multi_span) {
745 note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
746 }
747 for (span, msg) in iter::zip(multi_span, messages) {
748 note_span.push_span_label(span, msg);
749 }
750 err.span_note(
751 note_span,
752 "for a trait to be dyn compatible it needs to allow building a vtable\n\
753 for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>",
754 );
755
756 if trait_span.is_some() {
758 let mut potential_solutions: Vec<_> =
759 reported_violations.into_iter().map(|violation| violation.solution()).collect();
760 potential_solutions.sort();
761 potential_solutions.dedup();
763 for solution in potential_solutions {
764 solution.add_to(&mut err);
765 }
766 }
767
768 attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
769
770 err
771}
772
773fn attempt_dyn_to_enum_suggestion(
776 tcx: TyCtxt<'_>,
777 trait_def_id: DefId,
778 trait_str: &str,
779 err: &mut Diag<'_>,
780) {
781 let impls_of = tcx.trait_impls_of(trait_def_id);
782
783 if !impls_of.blanket_impls().is_empty() {
784 return;
785 }
786
787 let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
788 .non_blanket_impls()
789 .values()
790 .flatten()
791 .map(|impl_id| {
792 let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
795
796 match impl_type.kind() {
801 ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => {
802 return None;
803 }
804 _ => {}
805 }
806 Some(impl_type)
807 })
808 .collect();
809 let Some(concrete_impls) = concrete_impls else { return };
810
811 const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
812 if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
813 return;
814 }
815
816 let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
817 tcx.resolutions(()).effective_visibilities.is_exported(def_id)
821 } else {
822 false
823 };
824
825 if let [only_impl] = &concrete_impls[..] {
826 let within = if externally_visible { " within this crate" } else { "" };
827 err.help({
let _guard = NoTrimmedGuard::new();
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("only type `{0}` implements `{1}`{2}; consider using it directly instead.",
only_impl, trait_str, within))
})
}with_no_trimmed_paths!(format!(
828 "only type `{only_impl}` implements `{trait_str}`{within}; \
829 consider using it directly instead."
830 )));
831 } else {
832 let types = concrete_impls
833 .iter()
834 .map(|t| {
let _guard = NoTrimmedGuard::new();
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", t))
})
}with_no_trimmed_paths!(format!(" {}", t)))
835 .collect::<Vec<String>>()
836 .join("\n");
837
838 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the following types implement `{0}`:\n{1}\nconsider defining an enum where each variant holds one of these types,\nimplementing `{0}` for this new enum and using it instead",
trait_str, types))
})format!(
839 "the following types implement `{trait_str}`:\n\
840 {types}\n\
841 consider defining an enum where each variant holds one of these types,\n\
842 implementing `{trait_str}` for this new enum and using it instead",
843 ));
844 }
845
846 if externally_visible {
847 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` may be implemented in other crates; if you want to support your users passing their own types here, you can\'t refer to a specific type",
trait_str))
})format!(
848 "`{trait_str}` may be implemented in other crates; if you want to support your users \
849 passing their own types here, you can't refer to a specific type",
850 ));
851 }
852}
853
854fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
857 let Some(hir_id) = hir_id else { return };
858 let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
859 let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
860
861 let Some((_id, first_non_type_parent_node)) =
866 tcx.hir_parent_iter(hir_id).find(|(_id, node)| !#[allow(non_exhaustive_omitted_patterns)] match node {
hir::Node::Ty(_) => true,
_ => false,
}matches!(node, hir::Node::Ty(_)))
867 else {
868 return;
869 };
870 if first_non_type_parent_node.fn_sig().is_none() {
871 return;
872 }
873
874 err.span_suggestion_verbose(
875 ty.span.until(trait_ref.span),
876 "consider using an opaque type instead",
877 "impl ",
878 Applicability::MaybeIncorrect,
879 );
880}