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::InstantiateHigherRanked
235 | GoalSource::AliasWellFormed
236 ) && nested_goal.result().is_err()
237 },
238 )
239 })
240 });
241 }
242 }
243 }
244
245 candidates
246 }
247
248 fn visit_well_formed_goal(
252 &mut self,
253 candidate: &inspect::InspectCandidate<'_, 'tcx>,
254 term: ty::Term<'tcx>,
255 ) -> ControlFlow<PredicateObligation<'tcx>> {
256 let infcx = candidate.goal().infcx();
257 let param_env = candidate.goal().goal().param_env;
258 let body_id = self.obligation.cause.body_id;
259
260 for obligation in wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_id)
261 .into_iter()
262 .flatten()
263 {
264 let nested_goal = candidate.instantiate_proof_tree_for_nested_goal(
265 GoalSource::Misc,
266 obligation.as_goal(),
267 self.span(),
268 );
269 match (self.consider_ambiguities, nested_goal.result()) {
271 (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. }))
272 | (false, Err(_)) => {}
273 _ => continue,
274 }
275
276 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
277 }
278
279 ControlFlow::Break(self.obligation.clone())
280 }
281
282 fn detect_error_in_self_ty_normalization(
286 &mut self,
287 goal: &inspect::InspectGoal<'_, 'tcx>,
288 self_ty: Ty<'tcx>,
289 ) -> ControlFlow<PredicateObligation<'tcx>> {
290 assert!(!self.consider_ambiguities);
291 let tcx = goal.infcx().tcx;
292 if let ty::Alias(..) = self_ty.kind() {
293 let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
294 let pred = ty::PredicateKind::AliasRelate(
295 self_ty.into(),
296 infer_term.into(),
297 ty::AliasRelationDirection::Equate,
298 );
299 let obligation =
300 Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
301 self.with_derived_obligation(obligation, |this| {
302 goal.infcx().visit_proof_tree_at_depth(
303 goal.goal().with(tcx, pred),
304 goal.depth() + 1,
305 this,
306 )
307 })
308 } else {
309 ControlFlow::Continue(())
310 }
311 }
312
313 fn detect_trait_error_in_higher_ranked_projection(
321 &mut self,
322 goal: &inspect::InspectGoal<'_, 'tcx>,
323 ) -> ControlFlow<PredicateObligation<'tcx>> {
324 let tcx = goal.infcx().tcx;
325 if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
326 && !projection_clause.bound_vars().is_empty()
327 {
328 let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
329 let obligation = Obligation::new(
330 tcx,
331 self.obligation.cause.clone(),
332 goal.goal().param_env,
333 deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
334 );
335 self.with_derived_obligation(obligation, |this| {
336 goal.infcx().visit_proof_tree_at_depth(
337 goal.goal().with(tcx, pred),
338 goal.depth() + 1,
339 this,
340 )
341 })
342 } else {
343 ControlFlow::Continue(())
344 }
345 }
346
347 fn detect_non_well_formed_assoc_item(
354 &mut self,
355 goal: &inspect::InspectGoal<'_, 'tcx>,
356 alias: ty::AliasTerm<'tcx>,
357 ) -> ControlFlow<PredicateObligation<'tcx>> {
358 let tcx = goal.infcx().tcx;
359 let obligation = Obligation::new(
360 tcx,
361 self.obligation.cause.clone(),
362 goal.goal().param_env,
363 alias.trait_ref(tcx),
364 );
365 self.with_derived_obligation(obligation, |this| {
366 goal.infcx().visit_proof_tree_at_depth(
367 goal.goal().with(tcx, alias.trait_ref(tcx)),
368 goal.depth() + 1,
369 this,
370 )
371 })
372 }
373
374 fn detect_error_from_empty_candidates(
377 &mut self,
378 goal: &inspect::InspectGoal<'_, 'tcx>,
379 ) -> ControlFlow<PredicateObligation<'tcx>> {
380 let tcx = goal.infcx().tcx;
381 let pred_kind = goal.goal().predicate.kind();
382
383 match pred_kind.no_bound_vars() {
384 Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
385 self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
386 }
387 Some(ty::PredicateKind::NormalizesTo(pred))
388 if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst =
389 pred.alias.kind(tcx) =>
390 {
391 self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
392 self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
393 }
394 Some(_) | None => {}
395 }
396
397 ControlFlow::Break(self.obligation.clone())
398 }
399}
400
401impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
402 type Result = ControlFlow<PredicateObligation<'tcx>>;
403
404 fn span(&self) -> rustc_span::Span {
405 self.obligation.cause.span
406 }
407
408 #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
409 fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
410 let tcx = goal.infcx().tcx;
411 match (self.consider_ambiguities, goal.result()) {
413 (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. })) | (false, Err(_)) => {
414 }
415 _ => return ControlFlow::Continue(()),
416 }
417
418 let pred = goal.goal().predicate;
419
420 let candidates = self.non_trivial_candidates(goal);
421 let candidate = match candidates.as_slice() {
422 [candidate] => candidate,
423 [] => return self.detect_error_from_empty_candidates(goal),
424 _ => return ControlFlow::Break(self.obligation.clone()),
425 };
426
427 if let inspect::ProbeKind::TraitCandidate {
429 source: CandidateSource::Impl(impl_def_id),
430 result: _,
431 } = candidate.kind()
432 && tcx.do_not_recommend_impl(impl_def_id)
433 {
434 trace!("#[do_not_recommend] -> exit");
435 return ControlFlow::Break(self.obligation.clone());
436 }
437
438 let child_mode = match pred.kind().skip_binder() {
441 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
442 ChildMode::Trait(pred.kind().rebind(trait_pred))
443 }
444 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred)) => {
445 ChildMode::Host(pred.kind().rebind(host_pred))
446 }
447 ty::PredicateKind::NormalizesTo(normalizes_to)
448 if matches!(
449 normalizes_to.alias.kind(tcx),
450 ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
451 ) =>
452 {
453 ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
454 trait_ref: normalizes_to.alias.trait_ref(tcx),
455 polarity: ty::PredicatePolarity::Positive,
456 }))
457 }
458 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
459 return self.visit_well_formed_goal(candidate, term);
460 }
461 _ => ChildMode::PassThrough,
462 };
463
464 let nested_goals = candidate.instantiate_nested_goals(self.span());
465
466 for nested_goal in &nested_goals {
474 if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
475 && tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait)
476 && let Err(NoSolution) = nested_goal.result()
477 {
478 return ControlFlow::Break(self.obligation.clone());
479 }
480 }
481
482 let mut impl_where_bound_count = 0;
483 for nested_goal in nested_goals {
484 trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
485
486 let nested_pred = nested_goal.goal().predicate;
487
488 let make_obligation = |cause| Obligation {
489 cause,
490 param_env: nested_goal.goal().param_env,
491 predicate: nested_pred,
492 recursion_depth: self.obligation.recursion_depth + 1,
493 };
494
495 let obligation;
496 match (child_mode, nested_goal.source()) {
497 (
498 ChildMode::Trait(_) | ChildMode::Host(_),
499 GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
500 ) => {
501 continue;
502 }
503 (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
504 obligation = make_obligation(derive_cause(
505 tcx,
506 candidate.kind(),
507 self.obligation.cause.clone(),
508 impl_where_bound_count,
509 parent_trait_pred,
510 ));
511 impl_where_bound_count += 1;
512 }
513 (
514 ChildMode::Host(parent_host_pred),
515 GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
516 ) => {
517 obligation = make_obligation(derive_host_cause(
518 tcx,
519 candidate.kind(),
520 self.obligation.cause.clone(),
521 impl_where_bound_count,
522 parent_host_pred,
523 ));
524 impl_where_bound_count += 1;
525 }
526 (_, GoalSource::InstantiateHigherRanked) => {
528 obligation = self.obligation.clone();
529 }
530 (ChildMode::PassThrough, _)
531 | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
532 obligation = make_obligation(self.obligation.cause.clone());
533 }
534 }
535
536 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
537 }
538
539 if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred.kind().no_bound_vars() {
542 goal.infcx().visit_proof_tree_at_depth(
543 goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
544 goal.depth() + 1,
545 self,
546 )?;
547 goal.infcx().visit_proof_tree_at_depth(
548 goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
549 goal.depth() + 1,
550 self,
551 )?;
552 }
553
554 self.detect_trait_error_in_higher_ranked_projection(goal)?;
555
556 ControlFlow::Break(self.obligation.clone())
557 }
558}
559
560#[derive(Debug, Copy, Clone)]
561enum ChildMode<'tcx> {
562 Trait(ty::PolyTraitPredicate<'tcx>),
566 Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
570 PassThrough,
574}
575
576fn derive_cause<'tcx>(
577 tcx: TyCtxt<'tcx>,
578 candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
579 mut cause: ObligationCause<'tcx>,
580 idx: usize,
581 parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
582) -> ObligationCause<'tcx> {
583 match candidate_kind {
584 inspect::ProbeKind::TraitCandidate {
585 source: CandidateSource::Impl(impl_def_id),
586 result: _,
587 } => {
588 if let Some((_, span)) =
589 tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
590 {
591 cause = cause.derived_cause(parent_trait_pred, |derived| {
592 ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
593 derived,
594 impl_or_alias_def_id: impl_def_id,
595 impl_def_predicate_index: Some(idx),
596 span,
597 }))
598 })
599 }
600 }
601 inspect::ProbeKind::TraitCandidate {
602 source: CandidateSource::BuiltinImpl(..),
603 result: _,
604 } => {
605 cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
606 }
607 _ => {}
608 };
609 cause
610}
611
612fn derive_host_cause<'tcx>(
613 tcx: TyCtxt<'tcx>,
614 candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
615 mut cause: ObligationCause<'tcx>,
616 idx: usize,
617 parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
618) -> ObligationCause<'tcx> {
619 match candidate_kind {
620 inspect::ProbeKind::TraitCandidate {
621 source: CandidateSource::Impl(impl_def_id),
622 result: _,
623 } => {
624 if let Some((_, span)) = tcx
625 .predicates_of(impl_def_id)
626 .instantiate_identity(tcx)
627 .into_iter()
628 .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
629 |(trait_ref, span)| {
630 (
631 trait_ref.to_host_effect_clause(
632 tcx,
633 parent_host_pred.skip_binder().constness,
634 ),
635 span,
636 )
637 },
638 ))
639 .nth(idx)
640 {
641 cause =
642 cause.derived_host_cause(parent_host_pred, |derived| {
643 ObligationCauseCode::ImplDerivedHost(Box::new(
644 traits::ImplDerivedHostCause { derived, impl_def_id, span },
645 ))
646 })
647 }
648 }
649 inspect::ProbeKind::TraitCandidate {
650 source: CandidateSource::BuiltinImpl(..),
651 result: _,
652 } => {
653 cause =
654 cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
655 }
656 _ => {}
657 };
658 cause
659}