1use std::marker::PhantomData;
2
3use rustc_data_structures::captures::Captures;
4use rustc_data_structures::obligation_forest::{
5 Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult,
6};
7use rustc_infer::infer::DefineOpaqueTypes;
8use rustc_infer::traits::{
9 FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError,
10 TraitEngine,
11};
12use rustc_middle::bug;
13use rustc_middle::ty::abstract_const::NotConstEvaluatable;
14use rustc_middle::ty::error::{ExpectedFound, TypeError};
15use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
16use thin_vec::ThinVec;
17use tracing::{debug, debug_span, instrument};
18
19use super::effects::{self, HostEffectObligation};
20use super::project::{self, ProjectAndUnifyResult};
21use super::select::SelectionContext;
22use super::{
23 EvaluationResult, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
24 ScrubbedTraitError, Unimplemented, const_evaluatable, wf,
25};
26use crate::error_reporting::InferCtxtErrorExt;
27use crate::infer::{InferCtxt, TyOrConstInferVar};
28use crate::traits::EvaluateConstErr;
29use crate::traits::normalize::normalize_with_depth_to;
30use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
31use crate::traits::query::evaluate_obligation::InferCtxtExt;
32
33pub(crate) type PendingPredicateObligations<'tcx> = ThinVec<PendingPredicateObligation<'tcx>>;
34
35impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
36 type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>;
40
41 fn as_cache_key(&self) -> Self::CacheKey {
42 self.obligation.param_env.and(self.obligation.predicate)
43 }
44}
45
46pub struct FulfillmentContext<'tcx, E: 'tcx> {
57 predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
60
61 usable_in_snapshot: usize,
66
67 _errors: PhantomData<E>,
68}
69
70#[derive(Clone, Debug)]
71pub struct PendingPredicateObligation<'tcx> {
72 pub obligation: PredicateObligation<'tcx>,
73 pub stalled_on: Vec<TyOrConstInferVar>,
78}
79
80#[cfg(target_pointer_width = "64")]
82rustc_data_structures::static_assert_size!(PendingPredicateObligation<'_>, 72);
83
84impl<'tcx, E> FulfillmentContext<'tcx, E>
85where
86 E: FromSolverError<'tcx, OldSolverError<'tcx>>,
87{
88 pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx, E> {
90 assert!(
91 !infcx.next_trait_solver(),
92 "old trait solver fulfillment context created when \
93 infcx is set up for new trait solver"
94 );
95 FulfillmentContext {
96 predicates: ObligationForest::new(),
97 usable_in_snapshot: infcx.num_open_snapshots(),
98 _errors: PhantomData,
99 }
100 }
101
102 fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<E> {
104 let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
105 let _enter = span.enter();
106 let infcx = selcx.infcx;
107
108 let outcome: Outcome<_, _> =
110 self.predicates.process_obligations(&mut FulfillProcessor { selcx });
111
112 let errors: Vec<E> = outcome
116 .errors
117 .into_iter()
118 .map(|err| E::from_solver_error(infcx, OldSolverError(err)))
119 .collect();
120
121 debug!(
122 "select({} predicates remaining, {} errors) done",
123 self.predicates.len(),
124 errors.len()
125 );
126
127 errors
128 }
129}
130
131impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentContext<'tcx, E>
132where
133 E: FromSolverError<'tcx, OldSolverError<'tcx>>,
134{
135 #[inline]
136 fn register_predicate_obligation(
137 &mut self,
138 infcx: &InferCtxt<'tcx>,
139 mut obligation: PredicateObligation<'tcx>,
140 ) {
141 assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
142 debug_assert!(!obligation.param_env.has_non_region_infer());
145 obligation.predicate = infcx.resolve_vars_if_possible(obligation.predicate);
146
147 debug!(?obligation, "register_predicate_obligation");
148
149 self.predicates
150 .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
151 }
152
153 fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
154 self.predicates
155 .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None })
156 .into_iter()
157 .map(|err| E::from_solver_error(infcx, OldSolverError(err)))
158 .collect()
159 }
160
161 fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
162 let selcx = SelectionContext::new(infcx);
163 self.select(selcx)
164 }
165
166 fn drain_unstalled_obligations(
167 &mut self,
168 infcx: &InferCtxt<'tcx>,
169 ) -> PredicateObligations<'tcx> {
170 let mut processor =
171 DrainProcessor { removed_predicates: PredicateObligations::new(), infcx };
172 let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor);
173 assert!(outcome.errors.is_empty());
174 return processor.removed_predicates;
175
176 struct DrainProcessor<'a, 'tcx> {
177 infcx: &'a InferCtxt<'tcx>,
178 removed_predicates: PredicateObligations<'tcx>,
179 }
180
181 impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> {
182 type Obligation = PendingPredicateObligation<'tcx>;
183 type Error = !;
184 type OUT = Outcome<Self::Obligation, Self::Error>;
185
186 fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
187 pending_obligation
188 .stalled_on
189 .iter()
190 .any(|&var| self.infcx.ty_or_const_infer_var_changed(var))
191 }
192
193 fn process_obligation(
194 &mut self,
195 pending_obligation: &mut PendingPredicateObligation<'tcx>,
196 ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> {
197 assert!(self.needs_process_obligation(pending_obligation));
198 self.removed_predicates.push(pending_obligation.obligation.clone());
199 ProcessResult::Changed(Default::default())
200 }
201
202 fn process_backedge<'c, I>(
203 &mut self,
204 cycle: I,
205 _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
206 ) -> Result<(), !>
207 where
208 I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
209 {
210 self.removed_predicates.extend(cycle.map(|c| c.obligation.clone()));
211 Ok(())
212 }
213 }
214 }
215
216 fn has_pending_obligations(&self) -> bool {
217 self.predicates.has_pending_obligations()
218 }
219
220 fn pending_obligations(&self) -> PredicateObligations<'tcx> {
221 self.predicates.map_pending_obligations(|o| o.obligation.clone())
222 }
223}
224
225struct FulfillProcessor<'a, 'tcx> {
226 selcx: SelectionContext<'a, 'tcx>,
227}
228
229fn mk_pending<'tcx>(os: PredicateObligations<'tcx>) -> PendingPredicateObligations<'tcx> {
230 os.into_iter()
231 .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] })
232 .collect()
233}
234
235impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
236 type Obligation = PendingPredicateObligation<'tcx>;
237 type Error = FulfillmentErrorCode<'tcx>;
238 type OUT = Outcome<Self::Obligation, Self::Error>;
239
240 #[inline]
250 fn skippable_obligations<'b>(
251 &'b self,
252 it: impl Iterator<Item = &'b Self::Obligation>,
253 ) -> usize {
254 let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged();
255
256 it.take_while(|o| match o.stalled_on.as_slice() {
257 [o] => is_unchanged(*o),
258 _ => false,
259 })
260 .count()
261 }
262
263 #[inline(always)]
269 fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
270 let stalled_on = &pending_obligation.stalled_on;
274 match stalled_on.len() {
275 1 => self.selcx.infcx.ty_or_const_infer_var_changed(stalled_on[0]),
279
280 0 => true,
288
289 _ => (|| {
296 for &infer_var in stalled_on {
297 if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) {
298 return true;
299 }
300 }
301 false
302 })(),
303 }
304 }
305
306 #[inline(never)]
314 #[instrument(level = "debug", skip(self, pending_obligation))]
315 fn process_obligation(
316 &mut self,
317 pending_obligation: &mut PendingPredicateObligation<'tcx>,
318 ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
319 pending_obligation.stalled_on.truncate(0);
320
321 let obligation = &mut pending_obligation.obligation;
322
323 debug!(?obligation, "pre-resolve");
324
325 if obligation.predicate.has_non_region_infer() {
326 obligation.predicate = self.selcx.infcx.resolve_vars_if_possible(obligation.predicate);
327 }
328
329 let obligation = &pending_obligation.obligation;
330
331 let infcx = self.selcx.infcx;
332
333 if obligation.predicate.has_aliases() {
334 let mut obligations = PredicateObligations::new();
335 let predicate = normalize_with_depth_to(
336 &mut self.selcx,
337 obligation.param_env,
338 obligation.cause.clone(),
339 obligation.recursion_depth + 1,
340 obligation.predicate,
341 &mut obligations,
342 );
343 if predicate != obligation.predicate {
344 obligations.push(obligation.with(infcx.tcx, predicate));
345 return ProcessResult::Changed(mk_pending(obligations));
346 }
347 }
348 let binder = obligation.predicate.kind();
349 match binder.no_bound_vars() {
350 None => match binder.skip_binder() {
351 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) => {
355 let trait_obligation = obligation.with(infcx.tcx, binder.rebind(trait_ref));
356
357 self.process_trait_obligation(
358 obligation,
359 trait_obligation,
360 &mut pending_obligation.stalled_on,
361 )
362 }
363 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
364 let project_obligation = obligation.with(infcx.tcx, binder.rebind(data));
365
366 self.process_projection_obligation(
367 obligation,
368 project_obligation,
369 &mut pending_obligation.stalled_on,
370 )
371 }
372 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
373 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_))
374 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
375 | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
376 | ty::PredicateKind::DynCompatible(_)
377 | ty::PredicateKind::Subtype(_)
378 | ty::PredicateKind::Coerce(_)
379 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
380 | ty::PredicateKind::ConstEquate(..)
381 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
385 let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder));
386 let mut obligations = PredicateObligations::with_capacity(1);
387 obligations.push(obligation.with(infcx.tcx, pred));
388
389 ProcessResult::Changed(mk_pending(obligations))
390 }
391 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
392 ty::PredicateKind::NormalizesTo(..) => {
393 bug!("NormalizesTo is only used by the new solver")
394 }
395 ty::PredicateKind::AliasRelate(..) => {
396 bug!("AliasRelate is only used by the new solver")
397 }
398 },
399 Some(pred) => match pred {
400 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
401 let trait_obligation = obligation.with(infcx.tcx, Binder::dummy(data));
402
403 self.process_trait_obligation(
404 obligation,
405 trait_obligation,
406 &mut pending_obligation.stalled_on,
407 )
408 }
409
410 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
411 let host_obligation = obligation.with(infcx.tcx, data);
412
413 self.process_host_obligation(
414 host_obligation,
415 &mut pending_obligation.stalled_on,
416 )
417 }
418
419 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
420 if infcx.considering_regions {
421 infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
422 }
423
424 ProcessResult::Changed(Default::default())
425 }
426
427 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
428 t_a,
429 r_b,
430 ))) => {
431 if infcx.considering_regions {
432 infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
433 }
434 ProcessResult::Changed(Default::default())
435 }
436
437 ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => {
438 let project_obligation = obligation.with(infcx.tcx, Binder::dummy(*data));
439
440 self.process_projection_obligation(
441 obligation,
442 project_obligation,
443 &mut pending_obligation.stalled_on,
444 )
445 }
446
447 ty::PredicateKind::DynCompatible(trait_def_id) => {
448 if !self.selcx.tcx().is_dyn_compatible(trait_def_id) {
449 ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented))
450 } else {
451 ProcessResult::Changed(Default::default())
452 }
453 }
454
455 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
456 ty::PredicateKind::NormalizesTo(..) => {
457 bug!("NormalizesTo is only used by the new solver")
458 }
459 ty::PredicateKind::AliasRelate(..) => {
460 bug!("AliasRelate is only used by the new solver")
461 }
462 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
466 let ct = infcx.shallow_resolve_const(ct);
467 let ct_ty = match ct.kind() {
468 ty::ConstKind::Infer(var) => {
469 let var = match var {
470 ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid),
471 ty::InferConst::Fresh(_) => {
472 bug!("encountered fresh const in fulfill")
473 }
474 };
475 pending_obligation.stalled_on.clear();
476 pending_obligation.stalled_on.extend([var]);
477 return ProcessResult::Unchanged;
478 }
479 ty::ConstKind::Error(_) => {
480 return ProcessResult::Changed(PendingPredicateObligations::new());
481 }
482 ty::ConstKind::Value(cv) => cv.ty,
483 ty::ConstKind::Unevaluated(uv) => {
484 infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
485 }
486 ty::ConstKind::Expr(_) => {
490 return ProcessResult::Changed(mk_pending(PredicateObligations::new()));
491 }
492 ty::ConstKind::Placeholder(_) => {
493 bug!("placeholder const {:?} in old solver", ct)
494 }
495 ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
496 ty::ConstKind::Param(param_ct) => {
497 param_ct.find_ty_from_env(obligation.param_env)
498 }
499 };
500
501 match infcx.at(&obligation.cause, obligation.param_env).eq(
502 DefineOpaqueTypes::Yes,
504 ct_ty,
505 ty,
506 ) {
507 Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
508 Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
509 SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty: ty },
510 )),
511 }
512 }
513
514 _ if !self
519 .selcx
520 .tcx()
521 .recursion_limit()
522 .value_within_limit(obligation.recursion_depth) =>
523 {
524 self.selcx.infcx.err_ctxt().report_overflow_obligation(&obligation, false);
525 }
526
527 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
528 match wf::obligations(
529 self.selcx.infcx,
530 obligation.param_env,
531 obligation.cause.body_id,
532 obligation.recursion_depth + 1,
533 arg,
534 obligation.cause.span,
535 ) {
536 None => {
537 pending_obligation.stalled_on =
538 vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()];
539 ProcessResult::Unchanged
540 }
541 Some(os) => ProcessResult::Changed(mk_pending(os)),
542 }
543 }
544
545 ty::PredicateKind::Subtype(subtype) => {
546 match self.selcx.infcx.subtype_predicate(
547 &obligation.cause,
548 obligation.param_env,
549 Binder::dummy(subtype),
550 ) {
551 Err((a, b)) => {
552 pending_obligation.stalled_on =
554 vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
555 ProcessResult::Unchanged
556 }
557 Ok(Ok(mut ok)) => {
558 for subobligation in &mut ok.obligations {
559 subobligation.set_depth_from_parent(obligation.recursion_depth);
560 }
561 ProcessResult::Changed(mk_pending(ok.obligations))
562 }
563 Ok(Err(err)) => {
564 let expected_found = if subtype.a_is_expected {
565 ExpectedFound::new(subtype.a, subtype.b)
566 } else {
567 ExpectedFound::new(subtype.b, subtype.a)
568 };
569 ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err))
570 }
571 }
572 }
573
574 ty::PredicateKind::Coerce(coerce) => {
575 match self.selcx.infcx.coerce_predicate(
576 &obligation.cause,
577 obligation.param_env,
578 Binder::dummy(coerce),
579 ) {
580 Err((a, b)) => {
581 pending_obligation.stalled_on =
583 vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
584 ProcessResult::Unchanged
585 }
586 Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
587 Ok(Err(err)) => {
588 let expected_found = ExpectedFound::new(coerce.b, coerce.a);
589 ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err))
590 }
591 }
592 }
593
594 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
595 match const_evaluatable::is_const_evaluatable(
596 self.selcx.infcx,
597 uv,
598 obligation.param_env,
599 obligation.cause.span,
600 ) {
601 Ok(()) => ProcessResult::Changed(Default::default()),
602 Err(NotConstEvaluatable::MentionsInfer) => {
603 pending_obligation.stalled_on.clear();
604 pending_obligation.stalled_on.extend(
605 uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
606 );
607 ProcessResult::Unchanged
608 }
609 Err(
610 e @ NotConstEvaluatable::MentionsParam
611 | e @ NotConstEvaluatable::Error(_),
612 ) => ProcessResult::Error(FulfillmentErrorCode::Select(
613 SelectionError::NotConstEvaluatable(e),
614 )),
615 }
616 }
617
618 ty::PredicateKind::ConstEquate(c1, c2) => {
619 let tcx = self.selcx.tcx();
620 assert!(
621 tcx.features().generic_const_exprs(),
622 "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
623 );
624 {
629 let c1 = tcx.expand_abstract_consts(c1);
630 let c2 = tcx.expand_abstract_consts(c2);
631 debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2);
632
633 use rustc_hir::def::DefKind;
634 match (c1.kind(), c2.kind()) {
635 (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b))
636 if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
637 {
638 if let Ok(new_obligations) = infcx
639 .at(&obligation.cause, obligation.param_env)
640 .eq(
643 DefineOpaqueTypes::Yes,
644 ty::AliasTerm::from(a),
645 ty::AliasTerm::from(b),
646 )
647 {
648 return ProcessResult::Changed(mk_pending(
649 new_obligations.into_obligations(),
650 ));
651 }
652 }
653 (_, ty::ConstKind::Unevaluated(_))
654 | (ty::ConstKind::Unevaluated(_), _) => (),
655 (_, _) => {
656 if let Ok(new_obligations) = infcx
657 .at(&obligation.cause, obligation.param_env)
658 .eq(DefineOpaqueTypes::Yes, c1, c2)
661 {
662 return ProcessResult::Changed(mk_pending(
663 new_obligations.into_obligations(),
664 ));
665 }
666 }
667 }
668 }
669
670 let stalled_on = &mut pending_obligation.stalled_on;
671
672 let mut evaluate = |c: Const<'tcx>| {
673 if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
674 match super::try_evaluate_const(
675 self.selcx.infcx,
676 c,
677 obligation.param_env,
678 ) {
679 Ok(val) => Ok(val),
680 e @ Err(EvaluateConstErr::HasGenericsOrInfers) => {
681 stalled_on.extend(
682 unevaluated
683 .args
684 .iter()
685 .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
686 );
687 e
688 }
689 e @ Err(
690 EvaluateConstErr::EvaluationFailure(_)
691 | EvaluateConstErr::InvalidConstParamTy(_),
692 ) => e,
693 }
694 } else {
695 Ok(c)
696 }
697 };
698
699 match (evaluate(c1), evaluate(c2)) {
700 (Ok(c1), Ok(c2)) => {
701 match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
702 DefineOpaqueTypes::Yes,
705 c1,
706 c2,
707 ) {
708 Ok(inf_ok) => {
709 ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
710 }
711 Err(err) => {
712 ProcessResult::Error(FulfillmentErrorCode::ConstEquate(
713 ExpectedFound::new(c1, c2),
714 err,
715 ))
716 }
717 }
718 }
719 (Err(EvaluateConstErr::InvalidConstParamTy(e)), _)
720 | (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => {
721 ProcessResult::Error(FulfillmentErrorCode::Select(
722 SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
723 ))
724 }
725 (Err(EvaluateConstErr::EvaluationFailure(e)), _)
726 | (_, Err(EvaluateConstErr::EvaluationFailure(e))) => {
727 ProcessResult::Error(FulfillmentErrorCode::Select(
728 SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
729 ))
730 }
731 (Err(EvaluateConstErr::HasGenericsOrInfers), _)
732 | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
733 if c1.has_non_region_infer() || c2.has_non_region_infer() {
734 ProcessResult::Unchanged
735 } else {
736 let expected_found = ExpectedFound::new(c1, c2);
738 ProcessResult::Error(FulfillmentErrorCode::ConstEquate(
739 expected_found,
740 TypeError::ConstMismatch(expected_found),
741 ))
742 }
743 }
744 }
745 }
746 },
747 }
748 }
749
750 #[inline(never)]
751 fn process_backedge<'c, I>(
752 &mut self,
753 cycle: I,
754 _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
755 ) -> Result<(), FulfillmentErrorCode<'tcx>>
756 where
757 I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
758 {
759 if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
760 debug!("process_child_obligations: coinductive match");
761 Ok(())
762 } else {
763 let cycle = cycle.map(|c| c.obligation.clone()).collect();
764 Err(FulfillmentErrorCode::Cycle(cycle))
765 }
766 }
767}
768
769impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
770 #[instrument(level = "debug", skip(self, obligation, stalled_on))]
771 fn process_trait_obligation(
772 &mut self,
773 obligation: &PredicateObligation<'tcx>,
774 trait_obligation: PolyTraitObligation<'tcx>,
775 stalled_on: &mut Vec<TyOrConstInferVar>,
776 ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
777 let infcx = self.selcx.infcx;
778 if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
779 {
780 if infcx.predicate_must_hold_considering_regions(obligation) {
783 debug!(
784 "selecting trait at depth {} evaluated to holds",
785 obligation.recursion_depth
786 );
787 return ProcessResult::Changed(Default::default());
788 }
789 }
790
791 match self.selcx.poly_select(&trait_obligation) {
792 Ok(Some(impl_source)) => {
793 debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth);
794 ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
795 }
796 Ok(None) => {
797 debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth);
798
799 stalled_on.clear();
804 stalled_on.extend(args_infer_vars(
805 &self.selcx,
806 trait_obligation.predicate.map_bound(|pred| pred.trait_ref.args),
807 ));
808
809 debug!(
810 "process_predicate: pending obligation {:?} now stalled on {:?}",
811 infcx.resolve_vars_if_possible(obligation.clone()),
812 stalled_on
813 );
814
815 ProcessResult::Unchanged
816 }
817 Err(selection_err) => {
818 debug!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
819
820 ProcessResult::Error(FulfillmentErrorCode::Select(selection_err))
821 }
822 }
823 }
824
825 fn process_projection_obligation(
826 &mut self,
827 obligation: &PredicateObligation<'tcx>,
828 project_obligation: PolyProjectionObligation<'tcx>,
829 stalled_on: &mut Vec<TyOrConstInferVar>,
830 ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
831 let tcx = self.selcx.tcx();
832 let infcx = self.selcx.infcx;
833 if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
834 {
835 if infcx.predicate_must_hold_considering_regions(obligation) {
838 if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation(
839 &mut self.selcx,
840 &project_obligation,
841 ) {
842 infcx
846 .inner
847 .borrow_mut()
848 .projection_cache()
849 .complete(key, EvaluationResult::EvaluatedToOk);
850 }
851 return ProcessResult::Changed(Default::default());
852 } else {
853 debug!("Does NOT hold: {:?}", obligation);
854 }
855 }
856
857 match project::poly_project_and_unify_term(&mut self.selcx, &project_obligation) {
858 ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
859 ProjectAndUnifyResult::FailedNormalization => {
860 stalled_on.clear();
861 stalled_on.extend(args_infer_vars(
862 &self.selcx,
863 project_obligation.predicate.map_bound(|pred| pred.projection_term.args),
864 ));
865 ProcessResult::Unchanged
866 }
867 ProjectAndUnifyResult::Recursive => {
869 let mut obligations = PredicateObligations::with_capacity(1);
870 obligations.push(project_obligation.with(tcx, project_obligation.predicate));
871
872 ProcessResult::Changed(mk_pending(obligations))
873 }
874 ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
875 ProcessResult::Error(FulfillmentErrorCode::Project(e))
876 }
877 }
878 }
879
880 fn process_host_obligation(
881 &mut self,
882 host_obligation: HostEffectObligation<'tcx>,
883 stalled_on: &mut Vec<TyOrConstInferVar>,
884 ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
885 match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
886 Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
887 Err(effects::EvaluationFailure::Ambiguous) => {
888 stalled_on.clear();
889 stalled_on.extend(args_infer_vars(
890 &self.selcx,
891 ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
892 ));
893 ProcessResult::Unchanged
894 }
895 Err(effects::EvaluationFailure::NoSolution) => {
896 ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
897 }
898 }
899 }
900}
901
902fn args_infer_vars<'a, 'tcx>(
904 selcx: &SelectionContext<'a, 'tcx>,
905 args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
906) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> {
907 selcx
908 .infcx
909 .resolve_vars_if_possible(args)
910 .skip_binder() .iter()
912 .filter(|arg| arg.has_non_region_infer())
913 .flat_map(|arg| {
914 let mut walker = arg.walk();
915 while let Some(c) = walker.next() {
916 if !c.has_non_region_infer() {
917 walker.visited.remove(&c);
918 walker.skip_current_subtree();
919 }
920 }
921 walker.visited.into_iter()
922 })
923 .filter_map(TyOrConstInferVar::maybe_from_generic_arg)
924}
925
926#[derive(Debug)]
927pub struct OldSolverError<'tcx>(
928 Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>,
929);
930
931impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for FulfillmentError<'tcx> {
932 fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self {
933 let mut iter = error.0.backtrace.into_iter();
934 let obligation = iter.next().unwrap().obligation;
935 let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation);
938 FulfillmentError::new(obligation, error.0.error, root_obligation)
939 }
940}
941
942impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for ScrubbedTraitError<'tcx> {
943 fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self {
944 match error.0.error {
945 FulfillmentErrorCode::Select(_)
946 | FulfillmentErrorCode::Project(_)
947 | FulfillmentErrorCode::Subtype(_, _)
948 | FulfillmentErrorCode::ConstEquate(_, _) => ScrubbedTraitError::TrueError,
949 FulfillmentErrorCode::Ambiguity { overflow: _ } => ScrubbedTraitError::Ambiguity,
950 FulfillmentErrorCode::Cycle(cycle) => ScrubbedTraitError::Cycle(cycle),
951 }
952 }
953}