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