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