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 file = 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 match self.tainted_by_errors() {
215 None => {
216 let err = self.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 return err.emit();
224 }
225 Some(e) => return e,
226 }
227 }
228
229 let term = data
243 .trait_ref
244 .args
245 .iter()
246 .filter_map(ty::GenericArg::as_term)
247 .find(|s| s.has_non_region_infer());
248
249 let mut err = if let Some(term) = term {
250 self.emit_inference_failure_err(
251 obligation.cause.body_id,
252 span,
253 term,
254 TypeAnnotationNeeded::E0283,
255 true,
256 )
257 } else {
258 struct_span_code_err!(
259 self.dcx(),
260 span,
261 E0283,
262 "type annotations needed: cannot satisfy `{}`",
263 self.tcx.short_string(predicate, &mut file),
264 )
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 file);
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_item(*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 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 file);
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 } else {
550 struct_span_code_err!(
552 self.dcx(),
553 span,
554 E0284,
555 "type annotations needed: cannot satisfy `{predicate}`",
556 )
557 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
558 }
559 }
560
561 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
562 if let Err(e) = predicate.error_reported() {
563 return e;
564 }
565 if let Some(e) = self.tainted_by_errors() {
566 return e;
567 }
568 let term =
569 data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer());
570 if let Some(term) = term {
571 let err = self.emit_inference_failure_err(
572 obligation.cause.body_id,
573 span,
574 term,
575 TypeAnnotationNeeded::E0284,
576 true,
577 );
578 err
579 } else {
580 let predicate = self.tcx.short_string(predicate, &mut file);
582 struct_span_code_err!(
583 self.dcx(),
584 span,
585 E0284,
586 "type annotations needed: cannot satisfy `{predicate}`",
587 )
588 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
589 }
590 }
591
592 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
593 .emit_inference_failure_err(
594 obligation.cause.body_id,
595 span,
596 ct.into(),
597 TypeAnnotationNeeded::E0284,
598 true,
599 ),
600 ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
601 if term.is_infer() =>
602 {
603 if let Some(e) = self.tainted_by_errors() {
604 return e;
605 }
606 let alias = self.tcx.short_string(alias, &mut file);
607 struct_span_code_err!(
608 self.dcx(),
609 span,
610 E0284,
611 "type annotations needed: cannot normalize `{alias}`",
612 )
613 .with_span_label(span, format!("cannot normalize `{alias}`"))
614 }
615 ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => {
616 if let Some(e) = self.tainted_by_errors() {
617 return e;
618 }
619
620 let mut err;
621
622 if self.tcx.features().staged_api() {
623 err = self.dcx().struct_span_err(
624 span,
625 format!("unstable feature `{sym}` is used without being enabled."),
626 );
627
628 err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`"));
629 } else {
630 err = feature_err_unstable_feature_bound(
631 &self.tcx.sess,
632 sym,
633 span,
634 format!("use of unstable library feature `{sym}`"),
635 );
636 }
637 err
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 file);
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 }
653 };
654 *err.long_ty_path() = file;
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}