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::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_span::{DUMMY_SP, ErrorGuaranteed, Span};
16use tracing::{debug, instrument};
17
18use crate::error_reporting::TypeErrCtxt;
19use crate::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
20use crate::error_reporting::traits::{FindExprBySpan, to_pretty_impl_header};
21use crate::traits::ObligationCtxt;
22use crate::traits::query::evaluate_obligation::InferCtxtExt;
23
24#[derive(Debug)]
25pub enum CandidateSource {
26 DefId(DefId),
27 ParamEnv(Span),
28}
29
30pub fn compute_applicable_impls_for_diagnostics<'tcx>(
31 infcx: &InferCtxt<'tcx>,
32 obligation: &PolyTraitObligation<'tcx>,
33) -> Vec<CandidateSource> {
34 let tcx = infcx.tcx;
35 let param_env = obligation.param_env;
36
37 let predicate_polarity = obligation.predicate.skip_binder().polarity;
38
39 let impl_may_apply = |impl_def_id| {
40 let ocx = ObligationCtxt::new(infcx);
41 infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
42 let obligation_trait_ref = ocx.normalize(
43 &ObligationCause::dummy(),
44 param_env,
45 placeholder_obligation.trait_ref,
46 );
47
48 let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
49 let impl_trait_ref =
50 tcx.impl_trait_ref(impl_def_id).unwrap().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).unwrap();
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.select_where_possible().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.select_where_possible().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 predicates =
132 tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
133 for (pred, span) in elaborate(tcx, predicates.into_iter()) {
134 let kind = pred.kind();
135 if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
136 && param_env_candidate_may_apply(kind.rebind(trait_pred))
137 {
138 if kind.rebind(trait_pred.trait_ref)
139 == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
140 {
141 ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
142 } else {
143 ambiguities.push(CandidateSource::ParamEnv(span))
144 }
145 }
146 }
147
148 ambiguities
149}
150
151impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
152 #[instrument(skip(self), level = "debug")]
153 pub(super) fn maybe_report_ambiguity(
154 &self,
155 obligation: &PredicateObligation<'tcx>,
156 ) -> ErrorGuaranteed {
157 let predicate = self.resolve_vars_if_possible(obligation.predicate);
163 let span = obligation.cause.span;
164 let mut file = None;
165
166 debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
167
168 let bound_predicate = predicate.kind();
172 let mut err = match bound_predicate.skip_binder() {
173 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
174 let trait_pred = bound_predicate.rebind(data);
175 debug!(?trait_pred);
176
177 if let Err(e) = predicate.error_reported() {
178 return e;
179 }
180
181 if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) {
182 return guar;
185 }
186
187 if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) {
203 match self.tainted_by_errors() {
204 None => {
205 let err = self.emit_inference_failure_err(
206 obligation.cause.body_id,
207 span,
208 trait_pred.self_ty().skip_binder().into(),
209 TypeAnnotationNeeded::E0282,
210 false,
211 );
212 return err.emit();
213 }
214 Some(e) => return e,
215 }
216 }
217
218 let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
232
233 let mut err = if let Some(arg) = arg {
234 self.emit_inference_failure_err(
235 obligation.cause.body_id,
236 span,
237 arg,
238 TypeAnnotationNeeded::E0283,
239 true,
240 )
241 } else {
242 struct_span_code_err!(
243 self.dcx(),
244 span,
245 E0283,
246 "type annotations needed: cannot satisfy `{}`",
247 self.tcx.short_string(predicate, &mut file),
248 )
249 };
250
251 let mut ambiguities = compute_applicable_impls_for_diagnostics(
252 self.infcx,
253 &obligation.with(self.tcx, trait_pred),
254 );
255 let has_non_region_infer = trait_pred
256 .skip_binder()
257 .trait_ref
258 .args
259 .types()
260 .any(|t| !t.is_ty_or_numeric_infer());
261 if ambiguities.len() > 5 {
265 let infcx = self.infcx;
266 if !ambiguities.iter().all(|option| match option {
267 CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
268 CandidateSource::ParamEnv(_) => true,
269 }) {
270 ambiguities.retain(|option| match option {
272 CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
273 CandidateSource::ParamEnv(_) => true,
274 });
275 }
276 }
277 if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
278 if let Some(e) = self.tainted_by_errors()
279 && arg.is_none()
280 {
281 err.cancel();
286 return e;
287 }
288 self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
289 } else {
290 if let Some(e) = self.tainted_by_errors() {
291 err.cancel();
292 return e;
293 }
294 let pred = self.tcx.short_string(predicate, &mut file);
295 err.note(format!("cannot satisfy `{pred}`"));
296 let impl_candidates =
297 self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
298 if impl_candidates.len() < 40 {
299 self.report_similar_impl_candidates(
300 impl_candidates.as_slice(),
301 trait_pred,
302 obligation.cause.body_id,
303 &mut err,
304 false,
305 obligation.param_env,
306 );
307 }
308 }
309
310 if let ObligationCauseCode::WhereClause(def_id, _)
311 | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
312 {
313 self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id());
314 }
315
316 if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
317 && let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
318 {
319 let mut expr_finder = FindExprBySpan::new(span, self.tcx);
320 expr_finder.visit_expr(&body.value);
321
322 if let Some(hir::Expr {
323 kind:
324 hir::ExprKind::Call(
325 hir::Expr {
326 kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
327 ..
328 },
329 _,
330 )
331 | hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
332 ..
333 }) = expr_finder.result
334 && let [
335 ..,
336 trait_path_segment @ hir::PathSegment {
337 res: Res::Def(DefKind::Trait, trait_id),
338 ..
339 },
340 hir::PathSegment {
341 ident: assoc_item_ident,
342 res: Res::Def(_, item_id),
343 ..
344 },
345 ] = path.segments
346 && data.trait_ref.def_id == *trait_id
347 && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
348 && let None = self.tainted_by_errors()
349 {
350 let (verb, noun) = match self.tcx.associated_item(item_id).kind {
351 ty::AssocKind::Const => ("refer to the", "constant"),
352 ty::AssocKind::Fn => ("call", "function"),
353 ty::AssocKind::Type => ("refer to the", "type"),
356 };
357
358 err.cancel();
360 err = self.dcx().struct_span_err(
361 span,
362 format!(
363 "cannot {verb} associated {noun} on trait without specifying the \
364 corresponding `impl` type",
365 ),
366 );
367 err.code(E0790);
368
369 if let Some(local_def_id) = data.trait_ref.def_id.as_local()
370 && let hir::Node::Item(hir::Item {
371 kind: hir::ItemKind::Trait(_, _, trait_ident, _, _, trait_item_refs),
372 ..
373 }) = self.tcx.hir_node_by_def_id(local_def_id)
374 && let Some(method_ref) = trait_item_refs
375 .iter()
376 .find(|item_ref| item_ref.ident == *assoc_item_ident)
377 {
378 err.span_label(
379 method_ref.span,
380 format!("`{trait_ident}::{assoc_item_ident}` defined here"),
381 );
382 }
383
384 err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
385
386 let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
387
388 if let Some(impl_def_id) =
389 trait_impls.non_blanket_impls().values().flatten().next()
390 {
391 let non_blanket_impl_count =
392 trait_impls.non_blanket_impls().values().flatten().count();
393 let (message, self_types) = if non_blanket_impl_count == 1 {
396 (
397 "use the fully-qualified path to the only available \
398 implementation",
399 vec![format!(
400 "{}",
401 self.tcx.type_of(impl_def_id).instantiate_identity()
402 )],
403 )
404 } else if non_blanket_impl_count < 20 {
405 (
406 "use a fully-qualified path to one of the available \
407 implementations",
408 trait_impls
409 .non_blanket_impls()
410 .values()
411 .flatten()
412 .map(|id| {
413 format!(
414 "{}",
415 self.tcx.type_of(id).instantiate_identity()
416 )
417 })
418 .collect::<Vec<String>>(),
419 )
420 } else {
421 (
422 "use a fully-qualified path to a specific available \
423 implementation",
424 vec!["/* self type */".to_string()],
425 )
426 };
427 let suggestions: Vec<_> = self_types
428 .into_iter()
429 .map(|self_type| {
430 let mut suggestions = vec![(
431 path.span.shrink_to_lo(),
432 format!("<{self_type} as "),
433 )];
434 if let Some(generic_arg) = trait_path_segment.args {
435 let between_span = trait_path_segment
436 .ident
437 .span
438 .between(generic_arg.span_ext);
439 suggestions.push((between_span, "".to_string()));
442 suggestions.push((
443 generic_arg.span_ext.shrink_to_hi(),
444 ">".to_string(),
445 ));
446 } else {
447 suggestions.push((
448 trait_path_segment.ident.span.shrink_to_hi(),
449 ">".to_string(),
450 ));
451 }
452 suggestions
453 })
454 .collect();
455 err.multipart_suggestions(
456 message,
457 suggestions,
458 Applicability::MaybeIncorrect,
459 );
460 }
461 }
462 };
463
464 err
465 }
466
467 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
468 if let Err(e) = arg.error_reported() {
472 return e;
473 }
474 if let Some(e) = self.tainted_by_errors() {
475 return e;
476 }
477
478 self.emit_inference_failure_err(
479 obligation.cause.body_id,
480 span,
481 arg,
482 TypeAnnotationNeeded::E0282,
483 false,
484 )
485 }
486
487 ty::PredicateKind::Subtype(data) => {
488 if let Err(e) = data.error_reported() {
489 return e;
490 }
491 if let Some(e) = self.tainted_by_errors() {
492 return e;
493 }
494 let ty::SubtypePredicate { a_is_expected: _, a, b } = data;
495 assert!(a.is_ty_var() && b.is_ty_var());
497 self.emit_inference_failure_err(
498 obligation.cause.body_id,
499 span,
500 a.into(),
501 TypeAnnotationNeeded::E0282,
502 true,
503 )
504 }
505 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
506 if let Err(e) = predicate.error_reported() {
507 return e;
508 }
509 if let Some(e) = self.tainted_by_errors() {
510 return e;
511 }
512
513 if let Err(guar) = self
514 .tcx
515 .ensure_ok()
516 .coherent_trait(self.tcx.parent(data.projection_term.def_id))
517 {
518 return guar;
521 }
522 let arg = data
523 .projection_term
524 .args
525 .iter()
526 .chain(Some(data.term.into_arg()))
527 .find(|g| g.has_non_region_infer());
528 let predicate = self.tcx.short_string(predicate, &mut file);
529 if let Some(arg) = arg {
530 self.emit_inference_failure_err(
531 obligation.cause.body_id,
532 span,
533 arg,
534 TypeAnnotationNeeded::E0284,
535 true,
536 )
537 .with_note(format!("cannot satisfy `{predicate}`"))
538 } else {
539 struct_span_code_err!(
541 self.dcx(),
542 span,
543 E0284,
544 "type annotations needed: cannot satisfy `{predicate}`",
545 )
546 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
547 }
548 }
549
550 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
551 if let Err(e) = predicate.error_reported() {
552 return e;
553 }
554 if let Some(e) = self.tainted_by_errors() {
555 return e;
556 }
557 let arg = data.walk().find(|g| g.is_non_region_infer());
558 if let Some(arg) = arg {
559 let err = self.emit_inference_failure_err(
560 obligation.cause.body_id,
561 span,
562 arg,
563 TypeAnnotationNeeded::E0284,
564 true,
565 );
566 err
567 } else {
568 let predicate = self.tcx.short_string(predicate, &mut file);
570 struct_span_code_err!(
571 self.dcx(),
572 span,
573 E0284,
574 "type annotations needed: cannot satisfy `{predicate}`",
575 )
576 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
577 }
578 }
579
580 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
581 .emit_inference_failure_err(
582 obligation.cause.body_id,
583 span,
584 ct.into(),
585 TypeAnnotationNeeded::E0284,
586 true,
587 ),
588 ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
589 if term.is_infer() =>
590 {
591 if let Some(e) = self.tainted_by_errors() {
592 return e;
593 }
594 let alias = self.tcx.short_string(alias, &mut file);
595 struct_span_code_err!(
596 self.dcx(),
597 span,
598 E0284,
599 "type annotations needed: cannot normalize `{alias}`",
600 )
601 .with_span_label(span, format!("cannot normalize `{alias}`"))
602 }
603
604 _ => {
605 if let Some(e) = self.tainted_by_errors() {
606 return e;
607 }
608 let predicate = self.tcx.short_string(predicate, &mut file);
609 struct_span_code_err!(
610 self.dcx(),
611 span,
612 E0284,
613 "type annotations needed: cannot satisfy `{predicate}`",
614 )
615 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
616 }
617 };
618 *err.long_ty_path() = file;
619 self.note_obligation_cause(&mut err, obligation);
620 err.emit()
621 }
622
623 fn annotate_source_of_ambiguity(
624 &self,
625 err: &mut Diag<'_>,
626 ambiguities: &[CandidateSource],
627 predicate: ty::Predicate<'tcx>,
628 ) {
629 let mut spans = vec![];
630 let mut crates = vec![];
631 let mut post = vec![];
632 let mut has_param_env = false;
633 for ambiguity in ambiguities {
634 match ambiguity {
635 CandidateSource::DefId(impl_def_id) => match self.tcx.span_of_impl(*impl_def_id) {
636 Ok(span) => spans.push(span),
637 Err(name) => {
638 crates.push(name);
639 if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
640 post.push(header);
641 }
642 }
643 },
644 CandidateSource::ParamEnv(span) => {
645 has_param_env = true;
646 spans.push(*span);
647 }
648 }
649 }
650 let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
651 crate_names.sort();
652 crate_names.dedup();
653 post.sort();
654 post.dedup();
655
656 if self.tainted_by_errors().is_some()
657 && (crate_names.len() == 1
658 && spans.len() == 0
659 && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
660 || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
661 {
662 err.downgrade_to_delayed_bug();
668 return;
669 }
670
671 let msg = format!(
672 "multiple `impl`s{} satisfying `{}` found",
673 if has_param_env { " or `where` clauses" } else { "" },
674 predicate
675 );
676 let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
677 format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
678 } else if post.len() == 1 {
679 format!(": `{}`", post[0])
680 } else {
681 String::new()
682 };
683
684 match (spans.len(), crates.len(), crate_names.len()) {
685 (0, 0, 0) => {
686 err.note(format!("cannot satisfy `{predicate}`"));
687 }
688 (0, _, 1) => {
689 err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
690 }
691 (0, _, _) => {
692 err.note(format!(
693 "{} in the following crates: {}{}",
694 msg,
695 crate_names.join(", "),
696 post,
697 ));
698 }
699 (_, 0, 0) => {
700 let span: MultiSpan = spans.into();
701 err.span_note(span, msg);
702 }
703 (_, 1, 1) => {
704 let span: MultiSpan = spans.into();
705 err.span_note(span, msg);
706 err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
707 }
708 _ => {
709 let span: MultiSpan = spans.into();
710 err.span_note(span, msg);
711 err.note(format!(
712 "and more `impl`s found in the following crates: {}{}",
713 crate_names.join(", "),
714 post,
715 ));
716 }
717 }
718 }
719}
720
721struct HasNumericInferVisitor;
722
723impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
724 type Result = ControlFlow<()>;
725
726 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
727 if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
728 ControlFlow::Break(())
729 } else {
730 ControlFlow::Continue(())
731 }
732 }
733}