rustc_trait_selection/error_reporting/traits/
mod.rs1pub 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, LangItem};
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| match e.obligation.predicate.kind().skip_binder() {
166 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
167 if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) =>
168 {
169 1
170 }
171 ty::PredicateKind::Coerce(_) => 2,
172 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
173 _ => 0,
174 });
175
176 for (index, error) in errors.iter().enumerate() {
177 let mut span = error.obligation.cause.span;
180 let expn_data = span.ctxt().outer_expn_data();
181 if let ExpnKind::Desugaring(_) = expn_data.kind {
182 span = expn_data.call_site;
183 }
184
185 error_map
186 .entry(span)
187 .or_default()
188 .push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
189 }
190
191 let mut is_suppressed = vec![false; errors.len()];
194 for (_, error_set) in error_map.iter() {
195 for error in error_set {
197 if let Some(index) = error.index {
198 for error2 in error_set {
202 if error2.index.is_some_and(|index2| is_suppressed[index2]) {
203 continue;
207 }
208
209 if self.error_implies(error2.goal, error.goal)
210 && !(error2.index >= error.index
211 && self.error_implies(error.goal, error2.goal))
212 {
213 info!("skipping {:?} (implied by {:?})", error, error2);
214 is_suppressed[index] = true;
215 break;
216 }
217 }
218 }
219 }
220 }
221
222 let mut reported = None;
223
224 for from_expansion in [false, true] {
225 for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
226 if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
227 let guar = self.report_fulfillment_error(error);
228 self.infcx.set_tainted_by_errors(guar);
229 reported = Some(guar);
230 let mut span = error.obligation.cause.span;
233 let expn_data = span.ctxt().outer_expn_data();
234 if let ExpnKind::Desugaring(_) = expn_data.kind {
235 span = expn_data.call_site;
236 }
237 self.reported_trait_errors
238 .borrow_mut()
239 .entry(span)
240 .or_insert_with(|| (vec![], guar))
241 .0
242 .push(error.obligation.as_goal());
243 }
244 }
245 }
246
247 reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
251 }
252
253 #[instrument(skip(self), level = "debug")]
254 fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
255 let mut error = FulfillmentError {
256 obligation: error.obligation.clone(),
257 code: error.code.clone(),
258 root_obligation: error.root_obligation.clone(),
259 };
260 if matches!(
261 error.code,
262 FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
263 | FulfillmentErrorCode::Project(_)
264 ) && self.apply_do_not_recommend(&mut error.obligation)
265 {
266 error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
267 }
268
269 match error.code {
270 FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
271 error.obligation.clone(),
272 &error.root_obligation,
273 selection_error,
274 ),
275 FulfillmentErrorCode::Project(ref e) => {
276 self.report_projection_error(&error.obligation, e)
277 }
278 FulfillmentErrorCode::Ambiguity { overflow: None } => {
279 self.maybe_report_ambiguity(&error.obligation)
280 }
281 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
282 self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
283 }
284 FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
285 .report_mismatched_types(
286 &error.obligation.cause,
287 error.obligation.param_env,
288 expected_found.expected,
289 expected_found.found,
290 *err,
291 )
292 .emit(),
293 FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
294 let mut diag = self.report_mismatched_consts(
295 &error.obligation.cause,
296 error.obligation.param_env,
297 expected_found.expected,
298 expected_found.found,
299 *err,
300 );
301 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
302 if let ObligationCauseCode::WhereClause(..)
303 | ObligationCauseCode::WhereClauseInExpr(..) = code
304 {
305 self.note_obligation_cause_code(
306 error.obligation.cause.body_id,
307 &mut diag,
308 error.obligation.predicate,
309 error.obligation.param_env,
310 code,
311 &mut vec![],
312 &mut Default::default(),
313 );
314 }
315 diag.emit()
316 }
317 FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
318 }
319 }
320}
321
322pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
325 use std::fmt::Write;
326
327 let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
328 let mut w = "impl".to_owned();
329
330 let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
331
332 let mut types_without_default_bounds = FxIndexSet::default();
335 let sized_trait = tcx.lang_items().sized_trait();
336
337 let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
338 if !arg_names.is_empty() {
339 types_without_default_bounds.extend(args.types());
340 w.push('<');
341 w.push_str(&arg_names.join(", "));
342 w.push('>');
343 }
344
345 write!(
346 w,
347 " {}{} for {}",
348 tcx.impl_polarity(impl_def_id).as_str(),
349 trait_ref.print_only_trait_path(),
350 tcx.type_of(impl_def_id).instantiate_identity()
351 )
352 .unwrap();
353
354 let predicates = tcx.predicates_of(impl_def_id).predicates;
357 let mut pretty_predicates =
358 Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
359
360 for (p, _) in predicates {
361 if let Some(poly_trait_ref) = p.as_trait_clause() {
362 if Some(poly_trait_ref.def_id()) == sized_trait {
363 types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
365 continue;
366 }
367 }
368 pretty_predicates.push(p.to_string());
369 }
370
371 pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
372
373 if !pretty_predicates.is_empty() {
374 write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
375 }
376
377 w.push(';');
378 Some(w)
379}
380
381impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
382 pub fn report_extra_impl_obligation(
383 &self,
384 error_span: Span,
385 impl_item_def_id: LocalDefId,
386 trait_item_def_id: DefId,
387 requirement: &dyn fmt::Display,
388 ) -> Diag<'a> {
389 let mut err = struct_span_code_err!(
390 self.dcx(),
391 error_span,
392 E0276,
393 "impl has stricter requirements than trait"
394 );
395
396 if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) {
397 if let Some(span) = self.tcx.hir_span_if_local(trait_item_def_id) {
398 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
399 err.span_label(span, format!("definition of `{item_name}` from trait"));
400 }
401 }
402
403 err.span_label(error_span, format!("impl has extra requirement {requirement}"));
404
405 err
406 }
407}
408
409pub fn report_dyn_incompatibility<'tcx>(
410 tcx: TyCtxt<'tcx>,
411 span: Span,
412 hir_id: Option<hir::HirId>,
413 trait_def_id: DefId,
414 violations: &[DynCompatibilityViolation],
415) -> Diag<'tcx> {
416 let trait_str = tcx.def_path_str(trait_def_id);
417 let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
418 hir::Node::Item(item) => match item.kind {
419 hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => {
420 Some(ident.span)
421 }
422 _ => unreachable!(),
423 },
424 _ => None,
425 });
426
427 let mut err = struct_span_code_err!(
428 tcx.dcx(),
429 span,
430 E0038,
431 "the {} `{}` is not dyn compatible",
432 tcx.def_descr(trait_def_id),
433 trait_str
434 );
435 err.span_label(span, format!("`{trait_str}` is not dyn compatible"));
436
437 attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
438
439 let mut reported_violations = FxIndexSet::default();
440 let mut multi_span = vec![];
441 let mut messages = vec![];
442 for violation in violations {
443 if let DynCompatibilityViolation::SizedSelf(sp) = &violation
444 && !sp.is_empty()
445 {
446 reported_violations.insert(DynCompatibilityViolation::SizedSelf(vec![].into()));
449 }
450 if reported_violations.insert(violation.clone()) {
451 let spans = violation.spans();
452 let msg = if trait_span.is_none() || spans.is_empty() {
453 format!("the trait is not dyn compatible because {}", violation.error_msg())
454 } else {
455 format!("...because {}", violation.error_msg())
456 };
457 if spans.is_empty() {
458 err.note(msg);
459 } else {
460 for span in spans {
461 multi_span.push(span);
462 messages.push(msg.clone());
463 }
464 }
465 }
466 }
467 let has_multi_span = !multi_span.is_empty();
468 let mut note_span = MultiSpan::from_spans(multi_span.clone());
469 if let (Some(trait_span), true) = (trait_span, has_multi_span) {
470 note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
471 }
472 for (span, msg) in iter::zip(multi_span, messages) {
473 note_span.push_span_label(span, msg);
474 }
475 err.span_note(
476 note_span,
477 "for a trait to be dyn compatible it needs to allow building a vtable\n\
478 for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>",
479 );
480
481 if trait_span.is_some() {
483 let mut potential_solutions: Vec<_> =
484 reported_violations.into_iter().map(|violation| violation.solution()).collect();
485 potential_solutions.sort();
486 potential_solutions.dedup();
488 for solution in potential_solutions {
489 solution.add_to(&mut err);
490 }
491 }
492
493 attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
494
495 err
496}
497
498fn attempt_dyn_to_enum_suggestion(
501 tcx: TyCtxt<'_>,
502 trait_def_id: DefId,
503 trait_str: &str,
504 err: &mut Diag<'_>,
505) {
506 let impls_of = tcx.trait_impls_of(trait_def_id);
507
508 if !impls_of.blanket_impls().is_empty() {
509 return;
510 }
511
512 let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
513 .non_blanket_impls()
514 .values()
515 .flatten()
516 .map(|impl_id| {
517 let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
520
521 match impl_type.kind() {
526 ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => {
527 return None;
528 }
529 _ => {}
530 }
531 Some(impl_type)
532 })
533 .collect();
534 let Some(concrete_impls) = concrete_impls else { return };
535
536 const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
537 if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
538 return;
539 }
540
541 let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
542 tcx.resolutions(()).effective_visibilities.is_exported(def_id)
546 } else {
547 false
548 };
549
550 if let [only_impl] = &concrete_impls[..] {
551 let within = if externally_visible { " within this crate" } else { "" };
552 err.help(with_no_trimmed_paths!(format!(
553 "only type `{only_impl}` implements `{trait_str}`{within}; \
554 consider using it directly instead."
555 )));
556 } else {
557 let types = concrete_impls
558 .iter()
559 .map(|t| with_no_trimmed_paths!(format!(" {}", t)))
560 .collect::<Vec<String>>()
561 .join("\n");
562
563 err.help(format!(
564 "the following types implement `{trait_str}`:\n\
565 {types}\n\
566 consider defining an enum where each variant holds one of these types,\n\
567 implementing `{trait_str}` for this new enum and using it instead",
568 ));
569 }
570
571 if externally_visible {
572 err.note(format!(
573 "`{trait_str}` may be implemented in other crates; if you want to support your users \
574 passing their own types here, you can't refer to a specific type",
575 ));
576 }
577}
578
579fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
582 let Some(hir_id) = hir_id else { return };
583 let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
584 let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
585
586 let Some((_id, first_non_type_parent_node)) =
591 tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
592 else {
593 return;
594 };
595 if first_non_type_parent_node.fn_sig().is_none() {
596 return;
597 }
598
599 err.span_suggestion_verbose(
600 ty.span.until(trait_ref.span),
601 "consider using an opaque type instead",
602 "impl ",
603 Applicability::MaybeIncorrect,
604 );
605}