1pub mod ambiguity;
2pub mod call_kind;
3mod fulfillment_errors;
4pub mod on_unimplemented;
5pub mod on_unimplemented_condition;
6pub mod on_unimplemented_format;
7mod overflow;
8pub mod suggestions;
9
10use std::{fmt, iter};
11
12use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
13use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
14use rustc_hir::def_id::{DefId, LocalDefId};
15use rustc_hir::intravisit::Visitor;
16use rustc_hir::{self as hir, AmbigArg};
17use rustc_infer::traits::solve::Goal;
18use rustc_infer::traits::{
19 DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
20 PredicateObligation, SelectionError,
21};
22use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
23use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
24use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span};
25use tracing::{info, instrument};
26
27pub use self::overflow::*;
28use crate::error_reporting::TypeErrCtxt;
29use crate::traits::{FulfillmentError, FulfillmentErrorCode};
30
31#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
36pub enum CandidateSimilarity {
37 Exact { ignoring_lifetimes: bool },
38 Fuzzy { ignoring_lifetimes: bool },
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub struct ImplCandidate<'tcx> {
43 pub trait_ref: ty::TraitRef<'tcx>,
44 pub similarity: CandidateSimilarity,
45 impl_def_id: DefId,
46}
47
48enum GetSafeTransmuteErrorAndReason {
49 Silent,
50 Default,
51 Error { err_msg: String, safe_transmute_explanation: Option<String> },
52}
53
54pub struct FindExprBySpan<'hir> {
56 pub span: Span,
57 pub result: Option<&'hir hir::Expr<'hir>>,
58 pub ty_result: Option<&'hir hir::Ty<'hir>>,
59 pub include_closures: bool,
60 pub tcx: TyCtxt<'hir>,
61}
62
63impl<'hir> FindExprBySpan<'hir> {
64 pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
65 Self { span, result: None, ty_result: None, tcx, include_closures: false }
66 }
67}
68
69impl<'v> Visitor<'v> for FindExprBySpan<'v> {
70 type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
71
72 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
73 self.tcx
74 }
75
76 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
77 if self.span == ex.span {
78 self.result = Some(ex);
79 } else {
80 if let hir::ExprKind::Closure(..) = ex.kind
81 && self.include_closures
82 && let closure_header_sp = self.span.with_hi(ex.span.hi())
83 && closure_header_sp == ex.span
84 {
85 self.result = Some(ex);
86 }
87 hir::intravisit::walk_expr(self, ex);
88 }
89 }
90
91 fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
92 if self.span == ty.span {
93 self.ty_result = Some(ty.as_unambig_ty());
94 } else {
95 hir::intravisit::walk_ty(self, ty);
96 }
97 }
98}
99
100#[derive(Clone)]
102pub enum ArgKind {
103 Arg(String, String),
105
106 Tuple(Option<Span>, Vec<(String, String)>),
111}
112
113impl ArgKind {
114 fn empty() -> ArgKind {
115 ArgKind::Arg("_".to_owned(), "_".to_owned())
116 }
117
118 pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
121 match t.kind() {
122 ty::Tuple(tys) => ArgKind::Tuple(
123 span,
124 tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
125 ),
126 _ => ArgKind::Arg("_".to_owned(), t.to_string()),
127 }
128 }
129}
130
131#[derive(Copy, Clone)]
132pub enum DefIdOrName {
133 DefId(DefId),
134 Name(&'static str),
135}
136
137impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
138 pub fn report_fulfillment_errors(
139 &self,
140 mut errors: Vec<FulfillmentError<'tcx>>,
141 ) -> ErrorGuaranteed {
142 #[derive(Debug)]
143 struct ErrorDescriptor<'tcx> {
144 goal: Goal<'tcx, ty::Predicate<'tcx>>,
145 index: Option<usize>, }
147
148 let mut error_map: FxIndexMap<_, Vec<_>> = self
149 .reported_trait_errors
150 .borrow()
151 .iter()
152 .map(|(&span, goals)| {
153 (span, goals.0.iter().map(|&goal| ErrorDescriptor { goal, index: None }).collect())
154 })
155 .collect();
156
157 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
162 enum ErrorSortKey {
163 SubtypeFormat(usize, usize),
164 OtherKind,
165 SizedTrait,
166 MetaSizedTrait,
167 PointeeSizedTrait,
168 Coerce,
169 WellFormed,
170 }
171 errors.sort_by_key(|e| {
172 let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() {
173 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()),
174 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => Some(pred.def_id()),
175 _ => None,
176 };
177
178 match e.obligation.predicate.kind().skip_binder() {
179 ty::PredicateKind::Subtype(_)
180 if matches!(
181 e.obligation.cause.span.desugaring_kind(),
182 Some(DesugaringKind::FormatLiteral { .. })
183 ) =>
184 {
185 let (_, row, col, ..) =
186 self.tcx.sess.source_map().span_to_location_info(e.obligation.cause.span);
187 ErrorSortKey::SubtypeFormat(row, col)
188 }
189 _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => {
190 ErrorSortKey::SizedTrait
191 }
192 _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => {
193 ErrorSortKey::MetaSizedTrait
194 }
195 _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => {
196 ErrorSortKey::PointeeSizedTrait
197 }
198 ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce,
199 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
200 ErrorSortKey::WellFormed
201 }
202 _ => ErrorSortKey::OtherKind,
203 }
204 });
205
206 for (index, error) in errors.iter().enumerate() {
207 let mut span = error.obligation.cause.span;
210 let expn_data = span.ctxt().outer_expn_data();
211 if let ExpnKind::Desugaring(_) = expn_data.kind {
212 span = expn_data.call_site;
213 }
214
215 error_map
216 .entry(span)
217 .or_default()
218 .push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
219 }
220
221 let mut is_suppressed = vec![false; errors.len()];
224 for (_, error_set) in error_map.iter() {
225 for error in error_set {
227 if let Some(index) = error.index {
228 for error2 in error_set {
232 if error2.index.is_some_and(|index2| is_suppressed[index2]) {
233 continue;
237 }
238
239 if self.error_implies(error2.goal, error.goal)
240 && !(error2.index >= error.index
241 && self.error_implies(error.goal, error2.goal))
242 {
243 info!("skipping {:?} (implied by {:?})", error, error2);
244 is_suppressed[index] = true;
245 break;
246 }
247 }
248 }
249 }
250 }
251
252 let mut reported = None;
253
254 for from_expansion in [false, true] {
255 for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
256 if !suppressed
257 && error.obligation.cause.span.from_expansion() == from_expansion
258 && !error.references_error()
259 {
260 let guar = self.report_fulfillment_error(error);
261 self.infcx.set_tainted_by_errors(guar);
262 reported = Some(guar);
263 let mut span = error.obligation.cause.span;
266 let expn_data = span.ctxt().outer_expn_data();
267 if let ExpnKind::Desugaring(_) = expn_data.kind {
268 span = expn_data.call_site;
269 }
270 self.reported_trait_errors
271 .borrow_mut()
272 .entry(span)
273 .or_insert_with(|| (vec![], guar))
274 .0
275 .push(error.obligation.as_goal());
276 }
277 }
278 }
279
280 reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
284 }
285
286 #[instrument(skip(self), level = "debug")]
287 fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
288 let mut error = FulfillmentError {
289 obligation: error.obligation.clone(),
290 code: error.code.clone(),
291 root_obligation: error.root_obligation.clone(),
292 };
293 if matches!(
294 error.code,
295 FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
296 | FulfillmentErrorCode::Project(_)
297 ) && self.apply_do_not_recommend(&mut error.obligation)
298 {
299 error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
300 }
301
302 match error.code {
303 FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
304 error.obligation.clone(),
305 &error.root_obligation,
306 selection_error,
307 ),
308 FulfillmentErrorCode::Project(ref e) => {
309 self.report_projection_error(&error.obligation, e)
310 }
311 FulfillmentErrorCode::Ambiguity { overflow: None } => {
312 self.maybe_report_ambiguity(&error.obligation)
313 }
314 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
315 self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
316 }
317 FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
318 .report_mismatched_types(
319 &error.obligation.cause,
320 error.obligation.param_env,
321 expected_found.expected,
322 expected_found.found,
323 *err,
324 )
325 .emit(),
326 FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
327 let mut diag = self.report_mismatched_consts(
328 &error.obligation.cause,
329 error.obligation.param_env,
330 expected_found.expected,
331 expected_found.found,
332 *err,
333 );
334 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
335 if let ObligationCauseCode::WhereClause(..)
336 | ObligationCauseCode::WhereClauseInExpr(..) = code
337 {
338 self.note_obligation_cause_code(
339 error.obligation.cause.body_id,
340 &mut diag,
341 error.obligation.predicate,
342 error.obligation.param_env,
343 code,
344 &mut vec![],
345 &mut Default::default(),
346 );
347 }
348 diag.emit()
349 }
350 FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
351 }
352 }
353}
354
355pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
358 use std::fmt::Write;
359
360 let trait_ref = tcx.impl_opt_trait_ref(impl_def_id)?.instantiate_identity();
361 let mut w = "impl".to_owned();
362
363 #[derive(Debug, Default)]
364 struct SizednessFound {
365 sized: bool,
366 meta_sized: bool,
367 }
368
369 let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
370
371 let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
372
373 let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
374 if !arg_names.is_empty() {
375 w.push('<');
376 w.push_str(&arg_names.join(", "));
377 w.push('>');
378
379 for ty in args.types() {
380 types_with_sizedness_bounds.insert(ty, SizednessFound::default());
382 }
383 }
384
385 write!(
386 w,
387 " {}{} for {}",
388 tcx.impl_polarity(impl_def_id).as_str(),
389 trait_ref.print_only_trait_path(),
390 tcx.type_of(impl_def_id).instantiate_identity()
391 )
392 .unwrap();
393
394 let predicates = tcx.predicates_of(impl_def_id).predicates;
395 let mut pretty_predicates = Vec::with_capacity(predicates.len());
396
397 let sized_trait = tcx.lang_items().sized_trait();
398 let meta_sized_trait = tcx.lang_items().meta_sized_trait();
399
400 for (p, _) in predicates {
401 if let Some(trait_clause) = p.as_trait_clause() {
403 let self_ty = trait_clause.self_ty().skip_binder();
404 let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
405 if Some(trait_clause.def_id()) == sized_trait {
406 sizedness_of.sized = true;
407 continue;
408 } else if Some(trait_clause.def_id()) == meta_sized_trait {
409 sizedness_of.meta_sized = true;
410 continue;
411 }
412 }
413
414 pretty_predicates.push(p.to_string());
415 }
416
417 for (ty, sizedness) in types_with_sizedness_bounds {
418 if !tcx.features().sized_hierarchy() {
419 if sizedness.sized {
420 } else {
422 pretty_predicates.push(format!("{ty}: ?Sized"));
423 }
424 } else {
425 if sizedness.sized {
426 pretty_predicates.push(format!("{ty}: Sized"));
428 } else if sizedness.meta_sized {
429 pretty_predicates.push(format!("{ty}: MetaSized"));
430 } else {
431 pretty_predicates.push(format!("{ty}: PointeeSized"));
432 }
433 }
434 }
435
436 if !pretty_predicates.is_empty() {
437 write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
438 }
439
440 w.push(';');
441 Some(w)
442}
443
444impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
445 pub fn report_extra_impl_obligation(
446 &self,
447 error_span: Span,
448 impl_item_def_id: LocalDefId,
449 trait_item_def_id: DefId,
450 requirement: &dyn fmt::Display,
451 ) -> Diag<'a> {
452 let mut err = struct_span_code_err!(
453 self.dcx(),
454 error_span,
455 E0276,
456 "impl has stricter requirements than trait"
457 );
458
459 if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
460 if let Some(span) = self.tcx.hir_span_if_local(trait_item_def_id) {
461 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
462 err.span_label(span, format!("definition of `{item_name}` from trait"));
463 }
464 }
465
466 err.span_label(error_span, format!("impl has extra requirement {requirement}"));
467
468 err
469 }
470}
471
472pub fn report_dyn_incompatibility<'tcx>(
473 tcx: TyCtxt<'tcx>,
474 span: Span,
475 hir_id: Option<hir::HirId>,
476 trait_def_id: DefId,
477 violations: &[DynCompatibilityViolation],
478) -> Diag<'tcx> {
479 let trait_str = tcx.def_path_str(trait_def_id);
480 let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
481 hir::Node::Item(item) => match item.kind {
482 hir::ItemKind::Trait(_, _, _, ident, ..)
483 | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span),
484 _ => unreachable!(),
485 },
486 _ => None,
487 });
488
489 let mut err = struct_span_code_err!(
490 tcx.dcx(),
491 span,
492 E0038,
493 "the {} `{}` is not dyn compatible",
494 tcx.def_descr(trait_def_id),
495 trait_str
496 );
497 err.span_label(span, format!("`{trait_str}` is not dyn compatible"));
498
499 attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
500
501 let mut reported_violations = FxIndexSet::default();
502 let mut multi_span = vec![];
503 let mut messages = vec![];
504 for violation in violations {
505 if let DynCompatibilityViolation::SizedSelf(sp) = &violation
506 && !sp.is_empty()
507 {
508 reported_violations.insert(DynCompatibilityViolation::SizedSelf(vec![].into()));
511 }
512 if reported_violations.insert(violation.clone()) {
513 let spans = violation.spans();
514 let msg = if trait_span.is_none() || spans.is_empty() {
515 format!("the trait is not dyn compatible because {}", violation.error_msg())
516 } else {
517 format!("...because {}", violation.error_msg())
518 };
519 if spans.is_empty() {
520 err.note(msg);
521 } else {
522 for span in spans {
523 multi_span.push(span);
524 messages.push(msg.clone());
525 }
526 }
527 }
528 }
529 let has_multi_span = !multi_span.is_empty();
530 let mut note_span = MultiSpan::from_spans(multi_span.clone());
531 if let (Some(trait_span), true) = (trait_span, has_multi_span) {
532 note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
533 }
534 for (span, msg) in iter::zip(multi_span, messages) {
535 note_span.push_span_label(span, msg);
536 }
537 err.span_note(
538 note_span,
539 "for a trait to be dyn compatible it needs to allow building a vtable\n\
540 for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>",
541 );
542
543 if trait_span.is_some() {
545 let mut potential_solutions: Vec<_> =
546 reported_violations.into_iter().map(|violation| violation.solution()).collect();
547 potential_solutions.sort();
548 potential_solutions.dedup();
550 for solution in potential_solutions {
551 solution.add_to(&mut err);
552 }
553 }
554
555 attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
556
557 err
558}
559
560fn attempt_dyn_to_enum_suggestion(
563 tcx: TyCtxt<'_>,
564 trait_def_id: DefId,
565 trait_str: &str,
566 err: &mut Diag<'_>,
567) {
568 let impls_of = tcx.trait_impls_of(trait_def_id);
569
570 if !impls_of.blanket_impls().is_empty() {
571 return;
572 }
573
574 let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
575 .non_blanket_impls()
576 .values()
577 .flatten()
578 .map(|impl_id| {
579 let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
582
583 match impl_type.kind() {
588 ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => {
589 return None;
590 }
591 _ => {}
592 }
593 Some(impl_type)
594 })
595 .collect();
596 let Some(concrete_impls) = concrete_impls else { return };
597
598 const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
599 if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
600 return;
601 }
602
603 let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
604 tcx.resolutions(()).effective_visibilities.is_exported(def_id)
608 } else {
609 false
610 };
611
612 if let [only_impl] = &concrete_impls[..] {
613 let within = if externally_visible { " within this crate" } else { "" };
614 err.help(with_no_trimmed_paths!(format!(
615 "only type `{only_impl}` implements `{trait_str}`{within}; \
616 consider using it directly instead."
617 )));
618 } else {
619 let types = concrete_impls
620 .iter()
621 .map(|t| with_no_trimmed_paths!(format!(" {}", t)))
622 .collect::<Vec<String>>()
623 .join("\n");
624
625 err.help(format!(
626 "the following types implement `{trait_str}`:\n\
627 {types}\n\
628 consider defining an enum where each variant holds one of these types,\n\
629 implementing `{trait_str}` for this new enum and using it instead",
630 ));
631 }
632
633 if externally_visible {
634 err.note(format!(
635 "`{trait_str}` may be implemented in other crates; if you want to support your users \
636 passing their own types here, you can't refer to a specific type",
637 ));
638 }
639}
640
641fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
644 let Some(hir_id) = hir_id else { return };
645 let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
646 let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
647
648 let Some((_id, first_non_type_parent_node)) =
653 tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
654 else {
655 return;
656 };
657 if first_non_type_parent_node.fn_sig().is_none() {
658 return;
659 }
660
661 err.span_suggestion_verbose(
662 ty.span.until(trait_ref.span),
663 "consider using an opaque type instead",
664 "impl ",
665 Applicability::MaybeIncorrect,
666 );
667}