1use std::ops::ControlFlow;
2
3use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_span_code_err};
4use rustc_hir as hir;
5use rustc_hir::LangItem;
6use rustc_hir::def::{DefKind, Res};
7use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
8use rustc_hir::intravisit::Visitor as _;
9use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
10use rustc_infer::traits::util::elaborate;
11use rustc_infer::traits::{
12 Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
13};
14use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
15use rustc_session::parse::feature_err_unstable_feature_bound;
16use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
17use tracing::{debug, instrument};
18
19use crate::error_reporting::TypeErrCtxt;
20use crate::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
21use crate::error_reporting::traits::{FindExprBySpan, to_pretty_impl_header};
22use crate::traits::ObligationCtxt;
23use crate::traits::query::evaluate_obligation::InferCtxtExt;
24
25#[derive(Debug)]
26pub enum CandidateSource {
27 DefId(DefId),
28 ParamEnv(Span),
29}
30
31pub fn compute_applicable_impls_for_diagnostics<'tcx>(
32 infcx: &InferCtxt<'tcx>,
33 obligation: &PolyTraitObligation<'tcx>,
34) -> Vec<CandidateSource> {
35 let tcx = infcx.tcx;
36 let param_env = obligation.param_env;
37
38 let predicate_polarity = obligation.predicate.skip_binder().polarity;
39
40 let impl_may_apply = |impl_def_id| {
41 let ocx = ObligationCtxt::new(infcx);
42 infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
43 let obligation_trait_ref = ocx.normalize(
44 &ObligationCause::dummy(),
45 param_env,
46 placeholder_obligation.trait_ref,
47 );
48
49 let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
50 let impl_trait_ref =
51 tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
52 let impl_trait_ref =
53 ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
54
55 if let Err(_) =
56 ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
57 {
58 return false;
59 }
60
61 let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
62 let impl_polarity = impl_trait_header.polarity;
63
64 match (impl_polarity, predicate_polarity) {
65 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
66 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {}
67 _ => return false,
68 }
69
70 let obligations = tcx
71 .predicates_of(impl_def_id)
72 .instantiate(tcx, impl_args)
73 .into_iter()
74 .map(|(predicate, _)| {
75 Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
76 })
77 .filter(|obligation| {
82 infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok()
83 });
84 ocx.register_obligations(obligations);
85
86 ocx.select_where_possible().is_empty()
87 })
88 };
89
90 let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
91 let ocx = ObligationCtxt::new(infcx);
92 infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
93 let obligation_trait_ref = ocx.normalize(
94 &ObligationCause::dummy(),
95 param_env,
96 placeholder_obligation.trait_ref,
97 );
98
99 let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
100 DUMMY_SP,
101 BoundRegionConversionTime::HigherRankedType,
102 poly_trait_predicate,
103 );
104 let param_env_trait_ref =
105 ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
106
107 if let Err(_) = ocx.eq(
108 &ObligationCause::dummy(),
109 param_env,
110 obligation_trait_ref,
111 param_env_trait_ref,
112 ) {
113 return false;
114 }
115
116 ocx.select_where_possible().is_empty()
117 })
118 };
119
120 let mut ambiguities = Vec::new();
121
122 tcx.for_each_relevant_impl(
123 obligation.predicate.def_id(),
124 obligation.predicate.skip_binder().trait_ref.self_ty(),
125 |impl_def_id| {
126 if infcx.probe(|_| impl_may_apply(impl_def_id)) {
127 ambiguities.push(CandidateSource::DefId(impl_def_id))
128 }
129 },
130 );
131
132 let body_id = obligation.cause.body_id;
138 if body_id != CRATE_DEF_ID {
139 let predicates = tcx.predicates_of(body_id.to_def_id()).instantiate_identity(tcx);
140 for (pred, span) in elaborate(tcx, predicates.into_iter()) {
141 let kind = pred.kind();
142 if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
143 && param_env_candidate_may_apply(kind.rebind(trait_pred))
144 {
145 if kind.rebind(trait_pred.trait_ref)
146 == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
147 {
148 ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
149 } else {
150 ambiguities.push(CandidateSource::ParamEnv(span))
151 }
152 }
153 }
154 }
155
156 ambiguities
157}
158
159impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
160 #[instrument(skip(self), level = "debug")]
161 pub(super) fn maybe_report_ambiguity(
162 &self,
163 obligation: &PredicateObligation<'tcx>,
164 ) -> ErrorGuaranteed {
165 let predicate = self.resolve_vars_if_possible(obligation.predicate);
171 let span = obligation.cause.span;
172 let mut long_ty_path = None;
173
174 debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
175
176 let bound_predicate = predicate.kind();
180 let mut err = match bound_predicate.skip_binder() {
181 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
182 let trait_pred = bound_predicate.rebind(data);
183 debug!(?trait_pred);
184
185 if let Err(e) = predicate.error_reported() {
186 return e;
187 }
188
189 if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) {
190 return guar;
193 }
194
195 if matches!(
211 self.tcx.as_lang_item(trait_pred.def_id()),
212 Some(LangItem::Sized | LangItem::MetaSized)
213 ) {
214 return match self.tainted_by_errors() {
215 None => self
216 .emit_inference_failure_err(
217 obligation.cause.body_id,
218 span,
219 trait_pred.self_ty().skip_binder().into(),
220 TypeAnnotationNeeded::E0282,
221 false,
222 )
223 .emit(),
224 Some(e) => e,
225 };
226 }
227
228 let term = data
242 .trait_ref
243 .args
244 .iter()
245 .filter_map(ty::GenericArg::as_term)
246 .find(|s| s.has_non_region_infer());
247
248 let mut err = if let Some(term) = term {
249 self.emit_inference_failure_err(
250 obligation.cause.body_id,
251 span,
252 term,
253 TypeAnnotationNeeded::E0283,
254 true,
255 )
256 } else {
257 struct_span_code_err!(
258 self.dcx(),
259 span,
260 E0283,
261 "type annotations needed: cannot satisfy `{}`",
262 self.tcx.short_string(predicate, &mut long_ty_path),
263 )
264 .with_long_ty_path(long_ty_path)
265 };
266
267 let mut ambiguities = compute_applicable_impls_for_diagnostics(
268 self.infcx,
269 &obligation.with(self.tcx, trait_pred),
270 );
271 let has_non_region_infer = trait_pred
272 .skip_binder()
273 .trait_ref
274 .args
275 .types()
276 .any(|t| !t.is_ty_or_numeric_infer());
277 if ambiguities.len() > 5 {
281 let infcx = self.infcx;
282 if !ambiguities.iter().all(|option| match option {
283 CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
284 CandidateSource::ParamEnv(_) => true,
285 }) {
286 ambiguities.retain(|option| match option {
288 CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
289 CandidateSource::ParamEnv(_) => true,
290 });
291 }
292 }
293 if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
294 if let Some(e) = self.tainted_by_errors()
295 && term.is_none()
296 {
297 err.cancel();
302 return e;
303 }
304 self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
305 } else {
306 if let Some(e) = self.tainted_by_errors() {
307 err.cancel();
308 return e;
309 }
310 let pred = self.tcx.short_string(predicate, &mut err.long_ty_path());
311 err.note(format!("cannot satisfy `{pred}`"));
312 let impl_candidates =
313 self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
314 if impl_candidates.len() < 40 {
315 self.report_similar_impl_candidates(
316 impl_candidates.as_slice(),
317 trait_pred,
318 obligation.cause.body_id,
319 &mut err,
320 false,
321 obligation.param_env,
322 );
323 }
324 }
325
326 if let ObligationCauseCode::WhereClause(def_id, _)
327 | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
328 {
329 self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id());
330 }
331
332 if term.is_some_and(|term| term.as_type().is_some())
333 && let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
334 {
335 let mut expr_finder = FindExprBySpan::new(span, self.tcx);
336 expr_finder.visit_expr(&body.value);
337
338 if let Some(hir::Expr {
339 kind:
340 hir::ExprKind::Call(
341 hir::Expr {
342 kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
343 ..
344 },
345 _,
346 )
347 | hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
348 ..
349 }) = expr_finder.result
350 && let [
351 ..,
352 trait_path_segment @ hir::PathSegment {
353 res: Res::Def(DefKind::Trait, trait_id),
354 ..
355 },
356 hir::PathSegment {
357 ident: assoc_item_ident,
358 res: Res::Def(_, item_id),
359 ..
360 },
361 ] = path.segments
362 && data.trait_ref.def_id == *trait_id
363 && self.tcx.trait_of_assoc(*item_id) == Some(*trait_id)
364 && let None = self.tainted_by_errors()
365 {
366 let assoc_item = self.tcx.associated_item(item_id);
367 let (verb, noun) = match assoc_item.kind {
368 ty::AssocKind::Const { .. } => ("refer to the", "constant"),
369 ty::AssocKind::Fn { .. } => ("call", "function"),
370 ty::AssocKind::Type { .. } => ("refer to the", "type"),
373 };
374
375 err.cancel();
377 err = self.dcx().struct_span_err(
378 span,
379 format!(
380 "cannot {verb} associated {noun} on trait without specifying the \
381 corresponding `impl` type",
382 ),
383 );
384 err.code(E0790);
385
386 if item_id.is_local() {
387 let trait_ident = self.tcx.item_name(*trait_id);
388 err.span_label(
389 self.tcx.def_span(*item_id),
390 format!("`{trait_ident}::{assoc_item_ident}` defined here"),
391 );
392 }
393
394 err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
395
396 let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
397
398 if let Some(impl_def_id) =
399 trait_impls.non_blanket_impls().values().flatten().next()
400 {
401 let non_blanket_impl_count =
402 trait_impls.non_blanket_impls().values().flatten().count();
403 let (message, self_types) = if non_blanket_impl_count == 1 {
406 (
407 "use the fully-qualified path to the only available \
408 implementation",
409 vec![format!(
410 "{}",
411 self.tcx.type_of(impl_def_id).instantiate_identity()
412 )],
413 )
414 } else if non_blanket_impl_count < 20 {
415 (
416 "use a fully-qualified path to one of the available \
417 implementations",
418 trait_impls
419 .non_blanket_impls()
420 .values()
421 .flatten()
422 .map(|id| {
423 format!(
424 "{}",
425 self.tcx.type_of(id).instantiate_identity()
426 )
427 })
428 .collect::<Vec<String>>(),
429 )
430 } else {
431 (
432 "use a fully-qualified path to a specific available \
433 implementation",
434 vec!["/* self type */".to_string()],
435 )
436 };
437 let suggestions: Vec<_> = self_types
438 .into_iter()
439 .map(|self_type| {
440 let mut suggestions = vec![(
441 path.span.shrink_to_lo(),
442 format!("<{self_type} as "),
443 )];
444 if let Some(generic_arg) = trait_path_segment.args {
445 let between_span = trait_path_segment
446 .ident
447 .span
448 .between(generic_arg.span_ext);
449 suggestions.push((between_span, "".to_string()));
452 suggestions.push((
453 generic_arg.span_ext.shrink_to_hi(),
454 ">".to_string(),
455 ));
456 } else {
457 suggestions.push((
458 trait_path_segment.ident.span.shrink_to_hi(),
459 ">".to_string(),
460 ));
461 }
462 suggestions
463 })
464 .collect();
465 err.multipart_suggestions(
466 message,
467 suggestions,
468 Applicability::MaybeIncorrect,
469 );
470 }
471 }
472 };
473
474 err
475 }
476
477 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
478 if let Err(e) = term.error_reported() {
482 return e;
483 }
484 if let Some(e) = self.tainted_by_errors() {
485 return e;
486 }
487
488 self.emit_inference_failure_err(
489 obligation.cause.body_id,
490 span,
491 term,
492 TypeAnnotationNeeded::E0282,
493 false,
494 )
495 }
496
497 ty::PredicateKind::Subtype(data) => {
498 if let Err(e) = data.error_reported() {
499 return e;
500 }
501 if let Some(e) = self.tainted_by_errors() {
502 return e;
503 }
504 let ty::SubtypePredicate { a_is_expected: _, a, b } = data;
505 assert!(a.is_ty_var() && b.is_ty_var());
507 self.emit_inference_failure_err(
508 obligation.cause.body_id,
509 span,
510 a.into(),
511 TypeAnnotationNeeded::E0282,
512 true,
513 )
514 }
515
516 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
517 if let Err(e) = predicate.error_reported() {
518 return e;
519 }
520 if let Some(e) = self.tainted_by_errors() {
521 return e;
522 }
523
524 if let Err(guar) = self
525 .tcx
526 .ensure_ok()
527 .coherent_trait(self.tcx.parent(data.projection_term.def_id))
528 {
529 return guar;
532 }
533 let term = data
534 .projection_term
535 .args
536 .iter()
537 .filter_map(ty::GenericArg::as_term)
538 .chain([data.term])
539 .find(|g| g.has_non_region_infer());
540 let predicate = self.tcx.short_string(predicate, &mut long_ty_path);
541 if let Some(term) = term {
542 self.emit_inference_failure_err(
543 obligation.cause.body_id,
544 span,
545 term,
546 TypeAnnotationNeeded::E0284,
547 true,
548 )
549 .with_note(format!("cannot satisfy `{predicate}`"))
550 .with_long_ty_path(long_ty_path)
551 } else {
552 struct_span_code_err!(
554 self.dcx(),
555 span,
556 E0284,
557 "type annotations needed: cannot satisfy `{predicate}`",
558 )
559 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
560 .with_long_ty_path(long_ty_path)
561 }
562 }
563
564 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
565 if let Err(e) = predicate.error_reported() {
566 return e;
567 }
568 if let Some(e) = self.tainted_by_errors() {
569 return e;
570 }
571 let term =
572 data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer());
573 if let Some(term) = term {
574 self.emit_inference_failure_err(
575 obligation.cause.body_id,
576 span,
577 term,
578 TypeAnnotationNeeded::E0284,
579 true,
580 )
581 } else {
582 let predicate = self.tcx.short_string(predicate, &mut long_ty_path);
584 struct_span_code_err!(
585 self.dcx(),
586 span,
587 E0284,
588 "type annotations needed: cannot satisfy `{predicate}`",
589 )
590 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
591 .with_long_ty_path(long_ty_path)
592 }
593 }
594
595 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
596 .emit_inference_failure_err(
597 obligation.cause.body_id,
598 span,
599 ct.into(),
600 TypeAnnotationNeeded::E0284,
601 true,
602 ),
603
604 ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
605 if term.is_infer() =>
606 {
607 if let Some(e) = self.tainted_by_errors() {
608 return e;
609 }
610 let alias = self.tcx.short_string(alias, &mut long_ty_path);
611 struct_span_code_err!(
612 self.dcx(),
613 span,
614 E0284,
615 "type annotations needed: cannot normalize `{alias}`",
616 )
617 .with_span_label(span, format!("cannot normalize `{alias}`"))
618 .with_long_ty_path(long_ty_path)
619 }
620
621 ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => {
622 if let Some(e) = self.tainted_by_errors() {
623 return e;
624 }
625
626 if self.tcx.features().staged_api() {
627 self.dcx().struct_span_err(
628 span,
629 format!("unstable feature `{sym}` is used without being enabled."),
630 ).with_help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`"))
631 } else {
632 feature_err_unstable_feature_bound(
633 &self.tcx.sess,
634 sym,
635 span,
636 format!("use of unstable library feature `{sym}`"),
637 )
638 }
639 }
640
641 _ => {
642 if let Some(e) = self.tainted_by_errors() {
643 return e;
644 }
645 let predicate = self.tcx.short_string(predicate, &mut long_ty_path);
646 struct_span_code_err!(
647 self.dcx(),
648 span,
649 E0284,
650 "type annotations needed: cannot satisfy `{predicate}`",
651 )
652 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
653 .with_long_ty_path(long_ty_path)
654 }
655 };
656 self.note_obligation_cause(&mut err, obligation);
657 err.emit()
658 }
659
660 fn annotate_source_of_ambiguity(
661 &self,
662 err: &mut Diag<'_>,
663 ambiguities: &[CandidateSource],
664 predicate: ty::Predicate<'tcx>,
665 ) {
666 let mut spans = vec![];
667 let mut crates = vec![];
668 let mut post = vec![];
669 let mut has_param_env = false;
670 for ambiguity in ambiguities {
671 match ambiguity {
672 CandidateSource::DefId(impl_def_id) => match self.tcx.span_of_impl(*impl_def_id) {
673 Ok(span) => spans.push(span),
674 Err(name) => {
675 crates.push(name);
676 if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
677 post.push(header);
678 }
679 }
680 },
681 CandidateSource::ParamEnv(span) => {
682 has_param_env = true;
683 spans.push(*span);
684 }
685 }
686 }
687 let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
688 crate_names.sort();
689 crate_names.dedup();
690 post.sort();
691 post.dedup();
692
693 if self.tainted_by_errors().is_some()
694 && (crate_names.len() == 1
695 && spans.len() == 0
696 && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
697 || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
698 {
699 err.downgrade_to_delayed_bug();
705 return;
706 }
707
708 let msg = format!(
709 "multiple `impl`s{} satisfying `{}` found",
710 if has_param_env { " or `where` clauses" } else { "" },
711 predicate
712 );
713 let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
714 format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
715 } else if post.len() == 1 {
716 format!(": `{}`", post[0])
717 } else {
718 String::new()
719 };
720
721 match (spans.len(), crates.len(), crate_names.len()) {
722 (0, 0, 0) => {
723 err.note(format!("cannot satisfy `{predicate}`"));
724 }
725 (0, _, 1) => {
726 err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
727 }
728 (0, _, _) => {
729 err.note(format!(
730 "{} in the following crates: {}{}",
731 msg,
732 crate_names.join(", "),
733 post,
734 ));
735 }
736 (_, 0, 0) => {
737 let span: MultiSpan = spans.into();
738 err.span_note(span, msg);
739 }
740 (_, 1, 1) => {
741 let span: MultiSpan = spans.into();
742 err.span_note(span, msg);
743 err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
744 }
745 _ => {
746 let span: MultiSpan = spans.into();
747 err.span_note(span, msg);
748 err.note(format!(
749 "and more `impl`s found in the following crates: {}{}",
750 crate_names.join(", "),
751 post,
752 ));
753 }
754 }
755 }
756}
757
758struct HasNumericInferVisitor;
759
760impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
761 type Result = ControlFlow<()>;
762
763 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
764 if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
765 ControlFlow::Break(())
766 } else {
767 ControlFlow::Continue(())
768 }
769 }
770}