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