rustc_trait_selection/solve/fulfill/
derive_errors.rs1use std::ops::ControlFlow;
2
3use rustc_hir::LangItem;
4use rustc_infer::infer::InferCtxt;
5use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
6use rustc_infer::traits::{
7 self, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
8 PredicateObligation, SelectionError,
9};
10use rustc_middle::traits::query::NoSolution;
11use rustc_middle::ty::error::{ExpectedFound, TypeError};
12use rustc_middle::ty::{self, Ty, TyCtxt};
13use rustc_middle::{bug, span_bug};
14use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _};
15use tracing::{instrument, trace};
16
17use crate::solve::delegate::SolverDelegate;
18use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
19use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
20use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
21
22pub(super) fn fulfillment_error_for_no_solution<'tcx>(
23 infcx: &InferCtxt<'tcx>,
24 root_obligation: PredicateObligation<'tcx>,
25) -> FulfillmentError<'tcx> {
26 let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
27
28 let code = match obligation.predicate.kind().skip_binder() {
29 ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
30 FulfillmentErrorCode::Project(
31 MismatchedProjectionTypes { err: TypeError::Mismatch },
33 )
34 }
35 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => {
36 let ct_ty = match ct.kind() {
37 ty::ConstKind::Unevaluated(uv) => {
38 infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
39 }
40 ty::ConstKind::Param(param_ct) => {
41 param_ct.find_const_ty_from_env(obligation.param_env)
42 }
43 ty::ConstKind::Value(cv) => cv.ty,
44 kind => span_bug!(
45 obligation.cause.span,
46 "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
47 ),
48 };
49 FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType {
50 ct,
51 ct_ty,
52 expected_ty,
53 })
54 }
55 ty::PredicateKind::NormalizesTo(..) => {
56 FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
57 }
58 ty::PredicateKind::AliasRelate(_, _, _) => {
59 FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
60 }
61 ty::PredicateKind::Subtype(pred) => {
62 let (a, b) = infcx.enter_forall_and_leak_universe(
63 obligation.predicate.kind().rebind((pred.a, pred.b)),
64 );
65 let expected_found = ExpectedFound::new(a, b);
66 FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
67 }
68 ty::PredicateKind::Coerce(pred) => {
69 let (a, b) = infcx.enter_forall_and_leak_universe(
70 obligation.predicate.kind().rebind((pred.a, pred.b)),
71 );
72 let expected_found = ExpectedFound::new(b, a);
73 FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
74 }
75 ty::PredicateKind::Clause(_)
76 | ty::PredicateKind::DynCompatible(_)
77 | ty::PredicateKind::Ambiguous => {
78 FulfillmentErrorCode::Select(SelectionError::Unimplemented)
79 }
80 ty::PredicateKind::ConstEquate(..) => {
81 bug!("unexpected goal: {obligation:?}")
82 }
83 };
84
85 FulfillmentError { obligation, code, root_obligation }
86}
87
88pub(super) fn fulfillment_error_for_stalled<'tcx>(
89 infcx: &InferCtxt<'tcx>,
90 root_obligation: PredicateObligation<'tcx>,
91) -> FulfillmentError<'tcx> {
92 let (code, refine_obligation) = infcx.probe(|_| {
93 match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
94 root_obligation.as_goal(),
95 root_obligation.cause.span,
96 None,
97 ) {
98 Ok(GoalEvaluation {
99 certainty: Certainty::Maybe { cause: MaybeCause::Ambiguity, .. },
100 ..
101 }) => (FulfillmentErrorCode::Ambiguity { overflow: None }, true),
102 Ok(GoalEvaluation {
103 certainty:
104 Certainty::Maybe {
105 cause:
106 MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
107 ..
108 },
109 ..
110 }) => (
111 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
112 false,
119 ),
120 Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => {
121 span_bug!(
122 root_obligation.cause.span,
123 "did not expect successful goal when collecting ambiguity errors for `{:?}`",
124 infcx.resolve_vars_if_possible(root_obligation.predicate),
125 )
126 }
127 Err(_) => {
128 span_bug!(
129 root_obligation.cause.span,
130 "did not expect selection error when collecting ambiguity errors for `{:?}`",
131 infcx.resolve_vars_if_possible(root_obligation.predicate),
132 )
133 }
134 }
135 });
136
137 FulfillmentError {
138 obligation: if refine_obligation {
139 find_best_leaf_obligation(infcx, &root_obligation, true)
140 } else {
141 root_obligation.clone()
142 },
143 code,
144 root_obligation,
145 }
146}
147
148pub(super) fn fulfillment_error_for_overflow<'tcx>(
149 infcx: &InferCtxt<'tcx>,
150 root_obligation: PredicateObligation<'tcx>,
151) -> FulfillmentError<'tcx> {
152 FulfillmentError {
153 obligation: find_best_leaf_obligation(infcx, &root_obligation, true),
154 code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
155 root_obligation,
156 }
157}
158
159#[instrument(level = "debug", skip(infcx), ret)]
160fn find_best_leaf_obligation<'tcx>(
161 infcx: &InferCtxt<'tcx>,
162 obligation: &PredicateObligation<'tcx>,
163 consider_ambiguities: bool,
164) -> PredicateObligation<'tcx> {
165 let obligation = infcx.resolve_vars_if_possible(obligation.clone());
166 let obligation = infcx
172 .fudge_inference_if_ok(|| {
173 infcx
174 .visit_proof_tree(
175 obligation.as_goal(),
176 &mut BestObligation { obligation: obligation.clone(), consider_ambiguities },
177 )
178 .break_value()
179 .ok_or(())
180 })
181 .unwrap_or(obligation);
182 deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
183}
184
185struct BestObligation<'tcx> {
186 obligation: PredicateObligation<'tcx>,
187 consider_ambiguities: bool,
188}
189
190impl<'tcx> BestObligation<'tcx> {
191 fn with_derived_obligation(
192 &mut self,
193 derived_obligation: PredicateObligation<'tcx>,
194 and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result,
195 ) -> <Self as ProofTreeVisitor<'tcx>>::Result {
196 let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
197 let res = and_then(self);
198 self.obligation = old_obligation;
199 res
200 }
201
202 fn non_trivial_candidates<'a>(
207 &self,
208 goal: &'a inspect::InspectGoal<'a, 'tcx>,
209 ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
210 let mut candidates = goal.candidates();
211 match self.consider_ambiguities {
212 true => {
213 candidates.retain(|candidate| candidate.result().is_ok());
217 }
218 false => {
219 candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. }));
222 if candidates.len() > 1 {
226 candidates.retain(|candidate| {
227 goal.infcx().probe(|_| {
228 candidate.instantiate_nested_goals(self.span()).iter().any(
229 |nested_goal| {
230 matches!(
231 nested_goal.source(),
232 GoalSource::ImplWhereBound
233 | GoalSource::AliasBoundConstCondition
234 | GoalSource::AliasWellFormed
235 ) && nested_goal.result().is_err()
236 },
237 )
238 })
239 });
240 }
241 }
242 }
243
244 candidates
245 }
246
247 fn visit_well_formed_goal(
251 &mut self,
252 candidate: &inspect::InspectCandidate<'_, 'tcx>,
253 term: ty::Term<'tcx>,
254 ) -> ControlFlow<PredicateObligation<'tcx>> {
255 let infcx = candidate.goal().infcx();
256 let param_env = candidate.goal().goal().param_env;
257 let body_id = self.obligation.cause.body_id;
258
259 for obligation in wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_id)
260 .into_iter()
261 .flatten()
262 {
263 let nested_goal = candidate.instantiate_proof_tree_for_nested_goal(
264 GoalSource::Misc,
265 obligation.as_goal(),
266 self.span(),
267 );
268 match (self.consider_ambiguities, nested_goal.result()) {
270 (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. }))
271 | (false, Err(_)) => {}
272 _ => continue,
273 }
274
275 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
276 }
277
278 ControlFlow::Break(self.obligation.clone())
279 }
280
281 fn detect_error_in_self_ty_normalization(
285 &mut self,
286 goal: &inspect::InspectGoal<'_, 'tcx>,
287 self_ty: Ty<'tcx>,
288 ) -> ControlFlow<PredicateObligation<'tcx>> {
289 assert!(!self.consider_ambiguities);
290 let tcx = goal.infcx().tcx;
291 if let ty::Alias(..) = self_ty.kind() {
292 let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
293 let pred = ty::PredicateKind::AliasRelate(
294 self_ty.into(),
295 infer_term.into(),
296 ty::AliasRelationDirection::Equate,
297 );
298 let obligation =
299 Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
300 self.with_derived_obligation(obligation, |this| {
301 goal.infcx().visit_proof_tree_at_depth(
302 goal.goal().with(tcx, pred),
303 goal.depth() + 1,
304 this,
305 )
306 })
307 } else {
308 ControlFlow::Continue(())
309 }
310 }
311
312 fn detect_trait_error_in_higher_ranked_projection(
320 &mut self,
321 goal: &inspect::InspectGoal<'_, 'tcx>,
322 ) -> ControlFlow<PredicateObligation<'tcx>> {
323 let tcx = goal.infcx().tcx;
324 if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
325 && !projection_clause.bound_vars().is_empty()
326 {
327 let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
328 let obligation = Obligation::new(
329 tcx,
330 self.obligation.cause.clone(),
331 goal.goal().param_env,
332 deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
333 );
334 self.with_derived_obligation(obligation, |this| {
335 goal.infcx().visit_proof_tree_at_depth(
336 goal.goal().with(tcx, pred),
337 goal.depth() + 1,
338 this,
339 )
340 })
341 } else {
342 ControlFlow::Continue(())
343 }
344 }
345
346 fn detect_non_well_formed_assoc_item(
353 &mut self,
354 goal: &inspect::InspectGoal<'_, 'tcx>,
355 alias: ty::AliasTerm<'tcx>,
356 ) -> ControlFlow<PredicateObligation<'tcx>> {
357 let tcx = goal.infcx().tcx;
358 let obligation = Obligation::new(
359 tcx,
360 self.obligation.cause.clone(),
361 goal.goal().param_env,
362 alias.trait_ref(tcx),
363 );
364 self.with_derived_obligation(obligation, |this| {
365 goal.infcx().visit_proof_tree_at_depth(
366 goal.goal().with(tcx, alias.trait_ref(tcx)),
367 goal.depth() + 1,
368 this,
369 )
370 })
371 }
372
373 fn detect_error_from_empty_candidates(
376 &mut self,
377 goal: &inspect::InspectGoal<'_, 'tcx>,
378 ) -> ControlFlow<PredicateObligation<'tcx>> {
379 let tcx = goal.infcx().tcx;
380 let pred_kind = goal.goal().predicate.kind();
381
382 match pred_kind.no_bound_vars() {
383 Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
384 self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
385 }
386 Some(ty::PredicateKind::NormalizesTo(pred))
387 if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst =
388 pred.alias.kind(tcx) =>
389 {
390 self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
391 self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
392 }
393 Some(_) | None => {}
394 }
395
396 ControlFlow::Break(self.obligation.clone())
397 }
398}
399
400impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
401 type Result = ControlFlow<PredicateObligation<'tcx>>;
402
403 fn span(&self) -> rustc_span::Span {
404 self.obligation.cause.span
405 }
406
407 #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
408 fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
409 let tcx = goal.infcx().tcx;
410 match (self.consider_ambiguities, goal.result()) {
412 (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. })) | (false, Err(_)) => {
413 }
414 _ => return ControlFlow::Continue(()),
415 }
416
417 let pred = goal.goal().predicate;
418
419 let candidates = self.non_trivial_candidates(goal);
420 let candidate = match candidates.as_slice() {
421 [candidate] => candidate,
422 [] => return self.detect_error_from_empty_candidates(goal),
423 _ => return ControlFlow::Break(self.obligation.clone()),
424 };
425
426 if let inspect::ProbeKind::TraitCandidate {
428 source: CandidateSource::Impl(impl_def_id),
429 result: _,
430 } = candidate.kind()
431 && tcx.do_not_recommend_impl(impl_def_id)
432 {
433 trace!("#[do_not_recommend] -> exit");
434 return ControlFlow::Break(self.obligation.clone());
435 }
436
437 let child_mode = match pred.kind().skip_binder() {
440 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
441 ChildMode::Trait(pred.kind().rebind(trait_pred))
442 }
443 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred)) => {
444 ChildMode::Host(pred.kind().rebind(host_pred))
445 }
446 ty::PredicateKind::NormalizesTo(normalizes_to)
447 if matches!(
448 normalizes_to.alias.kind(tcx),
449 ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
450 ) =>
451 {
452 ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
453 trait_ref: normalizes_to.alias.trait_ref(tcx),
454 polarity: ty::PredicatePolarity::Positive,
455 }))
456 }
457 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
458 return self.visit_well_formed_goal(candidate, term);
459 }
460 _ => ChildMode::PassThrough,
461 };
462
463 let nested_goals = candidate.instantiate_nested_goals(self.span());
464
465 for nested_goal in &nested_goals {
473 if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
474 && tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait)
475 && let Err(NoSolution) = nested_goal.result()
476 {
477 return ControlFlow::Break(self.obligation.clone());
478 }
479 }
480
481 let mut impl_where_bound_count = 0;
482 for nested_goal in nested_goals {
483 trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
484
485 let nested_pred = nested_goal.goal().predicate;
486
487 let make_obligation = |cause| Obligation {
488 cause,
489 param_env: nested_goal.goal().param_env,
490 predicate: nested_pred,
491 recursion_depth: self.obligation.recursion_depth + 1,
492 };
493
494 let obligation;
495 match (child_mode, nested_goal.source()) {
496 (
497 ChildMode::Trait(_) | ChildMode::Host(_),
498 GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
499 ) => {
500 continue;
501 }
502 (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
503 obligation = make_obligation(derive_cause(
504 tcx,
505 candidate.kind(),
506 self.obligation.cause.clone(),
507 impl_where_bound_count,
508 parent_trait_pred,
509 ));
510 impl_where_bound_count += 1;
511 }
512 (
513 ChildMode::Host(parent_host_pred),
514 GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
515 ) => {
516 obligation = make_obligation(derive_host_cause(
517 tcx,
518 candidate.kind(),
519 self.obligation.cause.clone(),
520 impl_where_bound_count,
521 parent_host_pred,
522 ));
523 impl_where_bound_count += 1;
524 }
525 (ChildMode::PassThrough, _)
526 | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
527 obligation = make_obligation(self.obligation.cause.clone());
528 }
529 }
530
531 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
532 }
533
534 if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred.kind().no_bound_vars() {
537 goal.infcx().visit_proof_tree_at_depth(
538 goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
539 goal.depth() + 1,
540 self,
541 )?;
542 goal.infcx().visit_proof_tree_at_depth(
543 goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
544 goal.depth() + 1,
545 self,
546 )?;
547 }
548
549 self.detect_trait_error_in_higher_ranked_projection(goal)?;
550
551 ControlFlow::Break(self.obligation.clone())
552 }
553}
554
555#[derive(Debug, Copy, Clone)]
556enum ChildMode<'tcx> {
557 Trait(ty::PolyTraitPredicate<'tcx>),
561 Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
565 PassThrough,
569}
570
571fn derive_cause<'tcx>(
572 tcx: TyCtxt<'tcx>,
573 candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
574 mut cause: ObligationCause<'tcx>,
575 idx: usize,
576 parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
577) -> ObligationCause<'tcx> {
578 match candidate_kind {
579 inspect::ProbeKind::TraitCandidate {
580 source: CandidateSource::Impl(impl_def_id),
581 result: _,
582 } => {
583 if let Some((_, span)) =
584 tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
585 {
586 cause = cause.derived_cause(parent_trait_pred, |derived| {
587 ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
588 derived,
589 impl_or_alias_def_id: impl_def_id,
590 impl_def_predicate_index: Some(idx),
591 span,
592 }))
593 })
594 }
595 }
596 inspect::ProbeKind::TraitCandidate {
597 source: CandidateSource::BuiltinImpl(..),
598 result: _,
599 } => {
600 cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
601 }
602 _ => {}
603 };
604 cause
605}
606
607fn derive_host_cause<'tcx>(
608 tcx: TyCtxt<'tcx>,
609 candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
610 mut cause: ObligationCause<'tcx>,
611 idx: usize,
612 parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
613) -> ObligationCause<'tcx> {
614 match candidate_kind {
615 inspect::ProbeKind::TraitCandidate {
616 source: CandidateSource::Impl(impl_def_id),
617 result: _,
618 } => {
619 if let Some((_, span)) = tcx
620 .predicates_of(impl_def_id)
621 .instantiate_identity(tcx)
622 .into_iter()
623 .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
624 |(trait_ref, span)| {
625 (
626 trait_ref.to_host_effect_clause(
627 tcx,
628 parent_host_pred.skip_binder().constness,
629 ),
630 span,
631 )
632 },
633 ))
634 .nth(idx)
635 {
636 cause =
637 cause.derived_host_cause(parent_host_pred, |derived| {
638 ObligationCauseCode::ImplDerivedHost(Box::new(
639 traits::ImplDerivedHostCause { derived, impl_def_id, span },
640 ))
641 })
642 }
643 }
644 inspect::ProbeKind::TraitCandidate {
645 source: CandidateSource::BuiltinImpl(..),
646 result: _,
647 } => {
648 cause =
649 cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
650 }
651 _ => {}
652 };
653 cause
654}