1use std::mem;
2use std::ops::ControlFlow;
3
4#[cfg(feature = "nightly")]
5use rustc_macros::HashStable_NoContext;
6use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack};
7use rustc_type_ir::fast_reject::DeepRejectCtxt;
8use rustc_type_ir::inherent::*;
9use rustc_type_ir::relate::Relate;
10use rustc_type_ir::relate::solver_relating::RelateExt;
11use rustc_type_ir::search_graph::PathKind;
12use rustc_type_ir::{
13 self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder,
14 TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
15 TypingMode,
16};
17use tracing::{debug, instrument, trace};
18
19use super::has_only_region_constraints;
20use crate::coherence;
21use crate::delegate::SolverDelegate;
22use crate::solve::inspect::{self, ProofTreeBuilder};
23use crate::solve::search_graph::SearchGraph;
24use crate::solve::{
25 CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
26 GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
27 QueryResult,
28};
29
30pub(super) mod canonical;
31mod probe;
32
33#[derive(Debug, Copy, Clone)]
38enum CurrentGoalKind {
39 Misc,
40 CoinductiveTrait,
45 NormalizesTo,
53}
54
55impl CurrentGoalKind {
56 fn from_query_input<I: Interner>(cx: I, input: QueryInput<I, I::Predicate>) -> CurrentGoalKind {
57 match input.goal.predicate.kind().skip_binder() {
58 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
59 if cx.trait_is_coinductive(pred.trait_ref.def_id) {
60 CurrentGoalKind::CoinductiveTrait
61 } else {
62 CurrentGoalKind::Misc
63 }
64 }
65 ty::PredicateKind::NormalizesTo(_) => CurrentGoalKind::NormalizesTo,
66 _ => CurrentGoalKind::Misc,
67 }
68 }
69}
70
71pub struct EvalCtxt<'a, D, I = <D as SolverDelegate>::Interner>
72where
73 D: SolverDelegate<Interner = I>,
74 I: Interner,
75{
76 delegate: &'a D,
92
93 variables: I::CanonicalVarKinds,
96
97 current_goal_kind: CurrentGoalKind,
100 pub(super) var_values: CanonicalVarValues<I>,
101
102 pub(super) max_input_universe: ty::UniverseIndex,
112 pub(super) initial_opaque_types_storage_num_entries:
115 <D::Infcx as InferCtxtLike>::OpaqueTypeStorageEntries,
116
117 pub(super) search_graph: &'a mut SearchGraph<D>,
118
119 nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>,
120
121 pub(super) origin_span: I::Span,
122
123 tainted: Result<(), NoSolution>,
130
131 pub(super) inspect: ProofTreeBuilder<D>,
132}
133
134#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]
135#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
136pub enum GenerateProofTree {
137 Yes,
138 No,
139}
140
141pub trait SolverDelegateEvalExt: SolverDelegate {
142 fn evaluate_root_goal(
147 &self,
148 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
149 generate_proof_tree: GenerateProofTree,
150 span: <Self::Interner as Interner>::Span,
151 stalled_on: Option<GoalStalledOn<Self::Interner>>,
152 ) -> (
153 Result<GoalEvaluation<Self::Interner>, NoSolution>,
154 Option<inspect::GoalEvaluation<Self::Interner>>,
155 );
156
157 fn root_goal_may_hold_with_depth(
165 &self,
166 root_depth: usize,
167 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
168 ) -> bool;
169
170 fn evaluate_root_goal_raw(
173 &self,
174 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
175 generate_proof_tree: GenerateProofTree,
176 stalled_on: Option<GoalStalledOn<Self::Interner>>,
177 ) -> (
178 Result<
179 (NestedNormalizationGoals<Self::Interner>, GoalEvaluation<Self::Interner>),
180 NoSolution,
181 >,
182 Option<inspect::GoalEvaluation<Self::Interner>>,
183 );
184}
185
186impl<D, I> SolverDelegateEvalExt for D
187where
188 D: SolverDelegate<Interner = I>,
189 I: Interner,
190{
191 #[instrument(level = "debug", skip(self))]
192 fn evaluate_root_goal(
193 &self,
194 goal: Goal<I, I::Predicate>,
195 generate_proof_tree: GenerateProofTree,
196 span: I::Span,
197 stalled_on: Option<GoalStalledOn<I>>,
198 ) -> (Result<GoalEvaluation<I>, NoSolution>, Option<inspect::GoalEvaluation<I>>) {
199 EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| {
200 ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
201 })
202 }
203
204 fn root_goal_may_hold_with_depth(
205 &self,
206 root_depth: usize,
207 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
208 ) -> bool {
209 self.probe(|| {
210 EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| {
211 ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, None)
212 })
213 .0
214 })
215 .is_ok()
216 }
217
218 #[instrument(level = "debug", skip(self))]
219 fn evaluate_root_goal_raw(
220 &self,
221 goal: Goal<I, I::Predicate>,
222 generate_proof_tree: GenerateProofTree,
223 stalled_on: Option<GoalStalledOn<I>>,
224 ) -> (
225 Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution>,
226 Option<inspect::GoalEvaluation<I>>,
227 ) {
228 EvalCtxt::enter_root(
229 self,
230 self.cx().recursion_limit(),
231 generate_proof_tree,
232 I::Span::dummy(),
233 |ecx| {
234 ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
235 },
236 )
237 }
238}
239
240impl<'a, D, I> EvalCtxt<'a, D>
241where
242 D: SolverDelegate<Interner = I>,
243 I: Interner,
244{
245 pub(super) fn typing_mode(&self) -> TypingMode<I> {
246 self.delegate.typing_mode()
247 }
248
249 pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
258 match source {
259 GoalSource::Misc => PathKind::Unknown,
267 GoalSource::NormalizeGoal(path_kind) => path_kind,
268 GoalSource::ImplWhereBound => match self.current_goal_kind {
269 CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive,
272 CurrentGoalKind::NormalizesTo => PathKind::Inductive,
280 CurrentGoalKind::Misc => PathKind::Unknown,
284 },
285 GoalSource::TypeRelating => PathKind::Inductive,
289 GoalSource::InstantiateHigherRanked => PathKind::Inductive,
292 GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
296 }
297 }
298
299 pub(super) fn enter_root<R>(
303 delegate: &D,
304 root_depth: usize,
305 generate_proof_tree: GenerateProofTree,
306 origin_span: I::Span,
307 f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
308 ) -> (R, Option<inspect::GoalEvaluation<I>>) {
309 let mut search_graph = SearchGraph::new(root_depth);
310
311 let mut ecx = EvalCtxt {
312 delegate,
313 search_graph: &mut search_graph,
314 nested_goals: Default::default(),
315 inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree),
316
317 max_input_universe: ty::UniverseIndex::ROOT,
320 initial_opaque_types_storage_num_entries: Default::default(),
321 variables: Default::default(),
322 var_values: CanonicalVarValues::dummy(),
323 current_goal_kind: CurrentGoalKind::Misc,
324 origin_span,
325 tainted: Ok(()),
326 };
327 let result = f(&mut ecx);
328
329 let proof_tree = ecx.inspect.finalize();
330 assert!(
331 ecx.nested_goals.is_empty(),
332 "root `EvalCtxt` should not have any goals added to it"
333 );
334
335 assert!(search_graph.is_empty());
336 (result, proof_tree)
337 }
338
339 fn enter_canonical<R>(
348 cx: I,
349 search_graph: &'a mut SearchGraph<D>,
350 canonical_input: CanonicalInput<I>,
351 canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
352 f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
353 ) -> R {
354 let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input);
355
356 for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
357 let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy());
358 if let Some(prev) = prev {
370 debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
371 }
372 }
373
374 let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries();
375 let mut ecx = EvalCtxt {
376 delegate,
377 variables: canonical_input.canonical.variables,
378 var_values,
379 current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
380 max_input_universe: canonical_input.canonical.max_universe,
381 initial_opaque_types_storage_num_entries,
382 search_graph,
383 nested_goals: Default::default(),
384 origin_span: I::Span::dummy(),
385 tainted: Ok(()),
386 inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
387 };
388
389 let result = f(&mut ecx, input.goal);
390 ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe);
391 canonical_goal_evaluation.goal_evaluation_step(ecx.inspect);
392
393 delegate.reset_opaque_types();
399
400 result
401 }
402
403 #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
413 fn evaluate_canonical_goal(
414 cx: I,
415 search_graph: &'a mut SearchGraph<D>,
416 canonical_input: CanonicalInput<I>,
417 step_kind_from_parent: PathKind,
418 goal_evaluation: &mut ProofTreeBuilder<D>,
419 ) -> QueryResult<I> {
420 let mut canonical_goal_evaluation =
421 goal_evaluation.new_canonical_goal_evaluation(canonical_input);
422
423 let result = ensure_sufficient_stack(|| {
427 search_graph.with_new_goal(
428 cx,
429 canonical_input,
430 step_kind_from_parent,
431 &mut canonical_goal_evaluation,
432 |search_graph, canonical_goal_evaluation| {
433 EvalCtxt::enter_canonical(
434 cx,
435 search_graph,
436 canonical_input,
437 canonical_goal_evaluation,
438 |ecx, goal| {
439 let result = ecx.compute_goal(goal);
440 ecx.inspect.query_result(result);
441 result
442 },
443 )
444 },
445 )
446 });
447
448 canonical_goal_evaluation.query_result(result);
449 goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
450 result
451 }
452
453 fn evaluate_goal(
456 &mut self,
457 goal_evaluation_kind: GoalEvaluationKind,
458 source: GoalSource,
459 goal: Goal<I, I::Predicate>,
460 stalled_on: Option<GoalStalledOn<I>>,
461 ) -> Result<GoalEvaluation<I>, NoSolution> {
462 let (normalization_nested_goals, goal_evaluation) =
463 self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?;
464 assert!(normalization_nested_goals.is_empty());
465 Ok(goal_evaluation)
466 }
467
468 pub(super) fn evaluate_goal_raw(
476 &mut self,
477 goal_evaluation_kind: GoalEvaluationKind,
478 source: GoalSource,
479 goal: Goal<I, I::Predicate>,
480 stalled_on: Option<GoalStalledOn<I>>,
481 ) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution> {
482 if let Some(stalled_on) = stalled_on {
486 if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
487 && !self
488 .delegate
489 .opaque_types_storage_num_entries()
490 .needs_reevaluation(stalled_on.num_opaques)
491 {
492 return Ok((
493 NestedNormalizationGoals::empty(),
494 GoalEvaluation {
495 certainty: Certainty::Maybe(stalled_on.stalled_cause),
496 has_changed: HasChanged::No,
497 stalled_on: Some(stalled_on),
498 },
499 ));
500 }
501 }
502
503 let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
504 let mut goal_evaluation =
505 self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
506 let canonical_response = EvalCtxt::evaluate_canonical_goal(
507 self.cx(),
508 self.search_graph,
509 canonical_goal,
510 self.step_kind_for_source(source),
511 &mut goal_evaluation,
512 );
513 let response = match canonical_response {
514 Err(e) => {
515 self.inspect.goal_evaluation(goal_evaluation);
516 return Err(e);
517 }
518 Ok(response) => response,
519 };
520
521 let has_changed =
522 if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
523
524 let (normalization_nested_goals, certainty) =
525 self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response);
526 self.inspect.goal_evaluation(goal_evaluation);
527
528 let stalled_on = match certainty {
539 Certainty::Yes => None,
540 Certainty::Maybe(stalled_cause) => match has_changed {
541 HasChanged::Yes => None,
546 HasChanged::No => {
547 let mut stalled_vars = orig_values;
549 if let Some(normalizes_to) = goal.predicate.as_normalizes_to() {
550 let normalizes_to = normalizes_to.skip_binder();
551 let rhs_arg: I::GenericArg = normalizes_to.term.into();
552 let idx = stalled_vars
553 .iter()
554 .rposition(|arg| *arg == rhs_arg)
555 .expect("expected unconstrained arg");
556 stalled_vars.swap_remove(idx);
557 }
558
559 Some(GoalStalledOn {
560 num_opaques: canonical_goal
561 .canonical
562 .value
563 .predefined_opaques_in_body
564 .opaque_types
565 .len(),
566 stalled_vars,
567 stalled_cause,
568 })
569 }
570 },
571 };
572
573 Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on }))
574 }
575
576 fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
577 let Goal { param_env, predicate } = goal;
578 let kind = predicate.kind();
579 if let Some(kind) = kind.no_bound_vars() {
580 match kind {
581 ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
582 self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)
583 }
584 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
585 self.compute_host_effect_goal(Goal { param_env, predicate })
586 }
587 ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
588 self.compute_projection_goal(Goal { param_env, predicate })
589 }
590 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
591 self.compute_type_outlives_goal(Goal { param_env, predicate })
592 }
593 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
594 self.compute_region_outlives_goal(Goal { param_env, predicate })
595 }
596 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
597 self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
598 }
599 ty::PredicateKind::Subtype(predicate) => {
600 self.compute_subtype_goal(Goal { param_env, predicate })
601 }
602 ty::PredicateKind::Coerce(predicate) => {
603 self.compute_coerce_goal(Goal { param_env, predicate })
604 }
605 ty::PredicateKind::DynCompatible(trait_def_id) => {
606 self.compute_dyn_compatible_goal(trait_def_id)
607 }
608 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
609 self.compute_well_formed_goal(Goal { param_env, predicate: term })
610 }
611 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
612 self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
613 }
614 ty::PredicateKind::ConstEquate(_, _) => {
615 panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
616 }
617 ty::PredicateKind::NormalizesTo(predicate) => {
618 self.compute_normalizes_to_goal(Goal { param_env, predicate })
619 }
620 ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
621 .compute_alias_relate_goal(Goal {
622 param_env,
623 predicate: (lhs, rhs, direction),
624 }),
625 ty::PredicateKind::Ambiguous => {
626 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
627 }
628 }
629 } else {
630 self.enter_forall(kind, |ecx, kind| {
631 let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
632 ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
633 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
634 })
635 }
636 }
637
638 #[instrument(level = "trace", skip(self))]
641 pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
642 let mut response = Ok(Certainty::overflow(false));
643 for _ in 0..FIXPOINT_STEP_LIMIT {
644 match self.evaluate_added_goals_step() {
647 Ok(Some(cert)) => {
648 response = Ok(cert);
649 break;
650 }
651 Ok(None) => {}
652 Err(NoSolution) => {
653 response = Err(NoSolution);
654 break;
655 }
656 }
657 }
658
659 if response.is_err() {
660 self.tainted = Err(NoSolution);
661 }
662
663 response
664 }
665
666 fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> {
670 let cx = self.cx();
671 let mut unchanged_certainty = Some(Certainty::Yes);
673 for (source, goal, stalled_on) in mem::take(&mut self.nested_goals) {
674 if let Some(certainty) = self.delegate.compute_goal_fast_path(goal, self.origin_span) {
675 match certainty {
676 Certainty::Yes => {}
677 Certainty::Maybe(_) => {
678 self.nested_goals.push((source, goal, None));
679 unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
680 }
681 }
682 continue;
683 }
684
685 if let Some(pred) = goal.predicate.as_normalizes_to() {
696 let pred = pred.no_bound_vars().unwrap();
698 let unconstrained_rhs = self.next_term_infer_of_kind(pred.term);
701 let unconstrained_goal =
702 goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs });
703
704 let (
705 NestedNormalizationGoals(nested_goals),
706 GoalEvaluation { certainty, stalled_on, has_changed: _ },
707 ) = self.evaluate_goal_raw(
708 GoalEvaluationKind::Nested,
709 source,
710 unconstrained_goal,
711 stalled_on,
712 )?;
713 trace!(?nested_goals);
715 self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None)));
716
717 self.eq_structurally_relating_aliases(
732 goal.param_env,
733 pred.term,
734 unconstrained_rhs,
735 )?;
736
737 let with_resolved_vars = self.resolve_vars_if_possible(goal);
744 if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias {
745 unchanged_certainty = None;
746 }
747
748 match certainty {
749 Certainty::Yes => {}
750 Certainty::Maybe(_) => {
751 self.nested_goals.push((source, with_resolved_vars, stalled_on));
752 unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
753 }
754 }
755 } else {
756 let GoalEvaluation { certainty, has_changed, stalled_on } =
757 self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
758 if has_changed == HasChanged::Yes {
759 unchanged_certainty = None;
760 }
761
762 match certainty {
763 Certainty::Yes => {}
764 Certainty::Maybe(_) => {
765 self.nested_goals.push((source, goal, stalled_on));
766 unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
767 }
768 }
769 }
770 }
771
772 Ok(unchanged_certainty)
773 }
774
775 pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) {
777 self.inspect.record_impl_args(self.delegate, self.max_input_universe, impl_args)
778 }
779
780 pub(super) fn cx(&self) -> I {
781 self.delegate.cx()
782 }
783
784 #[instrument(level = "debug", skip(self))]
785 pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
786 goal.predicate =
787 goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env));
788 self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
789 self.nested_goals.push((source, goal, None));
790 }
791
792 #[instrument(level = "trace", skip(self, goals))]
793 pub(super) fn add_goals(
794 &mut self,
795 source: GoalSource,
796 goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
797 ) {
798 for goal in goals {
799 self.add_goal(source, goal);
800 }
801 }
802
803 pub(super) fn next_region_var(&mut self) -> I::Region {
804 let region = self.delegate.next_region_infer();
805 self.inspect.add_var_value(region);
806 region
807 }
808
809 pub(super) fn next_ty_infer(&mut self) -> I::Ty {
810 let ty = self.delegate.next_ty_infer();
811 self.inspect.add_var_value(ty);
812 ty
813 }
814
815 pub(super) fn next_const_infer(&mut self) -> I::Const {
816 let ct = self.delegate.next_const_infer();
817 self.inspect.add_var_value(ct);
818 ct
819 }
820
821 pub(super) fn next_term_infer_of_kind(&mut self, term: I::Term) -> I::Term {
824 match term.kind() {
825 ty::TermKind::Ty(_) => self.next_ty_infer().into(),
826 ty::TermKind::Const(_) => self.next_const_infer().into(),
827 }
828 }
829
830 #[instrument(level = "trace", skip(self), ret)]
835 pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
836 let universe_of_term = match goal.predicate.term.kind() {
837 ty::TermKind::Ty(ty) => {
838 if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
839 self.delegate.universe_of_ty(vid).unwrap()
840 } else {
841 return false;
842 }
843 }
844 ty::TermKind::Const(ct) => {
845 if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
846 self.delegate.universe_of_ct(vid).unwrap()
847 } else {
848 return false;
849 }
850 }
851 };
852
853 struct ContainsTermOrNotNameable<'a, D: SolverDelegate<Interner = I>, I: Interner> {
854 term: I::Term,
855 universe_of_term: ty::UniverseIndex,
856 delegate: &'a D,
857 cache: HashSet<I::Ty>,
858 }
859
860 impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
861 fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
862 if self.universe_of_term.can_name(universe) {
863 ControlFlow::Continue(())
864 } else {
865 ControlFlow::Break(())
866 }
867 }
868 }
869
870 impl<D: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
871 for ContainsTermOrNotNameable<'_, D, I>
872 {
873 type Result = ControlFlow<()>;
874 fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
875 if self.cache.contains(&t) {
876 return ControlFlow::Continue(());
877 }
878
879 match t.kind() {
880 ty::Infer(ty::TyVar(vid)) => {
881 if let ty::TermKind::Ty(term) = self.term.kind() {
882 if let ty::Infer(ty::TyVar(term_vid)) = term.kind() {
883 if self.delegate.root_ty_var(vid)
884 == self.delegate.root_ty_var(term_vid)
885 {
886 return ControlFlow::Break(());
887 }
888 }
889 }
890
891 self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
892 }
893 ty::Placeholder(p) => self.check_nameable(p.universe())?,
894 _ => {
895 if t.has_non_region_infer() || t.has_placeholders() {
896 t.super_visit_with(self)?
897 }
898 }
899 }
900
901 assert!(self.cache.insert(t));
902 ControlFlow::Continue(())
903 }
904
905 fn visit_const(&mut self, c: I::Const) -> Self::Result {
906 match c.kind() {
907 ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
908 if let ty::TermKind::Const(term) = self.term.kind() {
909 if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
910 {
911 if self.delegate.root_const_var(vid)
912 == self.delegate.root_const_var(term_vid)
913 {
914 return ControlFlow::Break(());
915 }
916 }
917 }
918
919 self.check_nameable(self.delegate.universe_of_ct(vid).unwrap())
920 }
921 ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
922 _ => {
923 if c.has_non_region_infer() || c.has_placeholders() {
924 c.super_visit_with(self)
925 } else {
926 ControlFlow::Continue(())
927 }
928 }
929 }
930 }
931
932 fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result {
933 if p.has_non_region_infer() || p.has_placeholders() {
934 p.super_visit_with(self)
935 } else {
936 ControlFlow::Continue(())
937 }
938 }
939
940 fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result {
941 if c.has_non_region_infer() || c.has_placeholders() {
942 c.super_visit_with(self)
943 } else {
944 ControlFlow::Continue(())
945 }
946 }
947 }
948
949 let mut visitor = ContainsTermOrNotNameable {
950 delegate: self.delegate,
951 universe_of_term,
952 term: goal.predicate.term,
953 cache: Default::default(),
954 };
955 goal.predicate.alias.visit_with(&mut visitor).is_continue()
956 && goal.param_env.visit_with(&mut visitor).is_continue()
957 }
958
959 #[instrument(level = "trace", skip(self, param_env), ret)]
960 pub(super) fn eq<T: Relate<I>>(
961 &mut self,
962 param_env: I::ParamEnv,
963 lhs: T,
964 rhs: T,
965 ) -> Result<(), NoSolution> {
966 self.relate(param_env, lhs, ty::Variance::Invariant, rhs)
967 }
968
969 #[instrument(level = "trace", skip(self, param_env), ret)]
975 pub(super) fn relate_rigid_alias_non_alias(
976 &mut self,
977 param_env: I::ParamEnv,
978 alias: ty::AliasTerm<I>,
979 variance: ty::Variance,
980 term: I::Term,
981 ) -> Result<(), NoSolution> {
982 if term.is_infer() {
985 let cx = self.cx();
986 let identity_args = self.fresh_args_for_item(alias.def_id);
995 let rigid_ctor = ty::AliasTerm::new_from_args(cx, alias.def_id, identity_args);
996 let ctor_term = rigid_ctor.to_term(cx);
997 let obligations = self.delegate.eq_structurally_relating_aliases(
998 param_env,
999 term,
1000 ctor_term,
1001 self.origin_span,
1002 )?;
1003 debug_assert!(obligations.is_empty());
1004 self.relate(param_env, alias, variance, rigid_ctor)
1005 } else {
1006 Err(NoSolution)
1007 }
1008 }
1009
1010 #[instrument(level = "trace", skip(self, param_env), ret)]
1014 pub(super) fn eq_structurally_relating_aliases<T: Relate<I>>(
1015 &mut self,
1016 param_env: I::ParamEnv,
1017 lhs: T,
1018 rhs: T,
1019 ) -> Result<(), NoSolution> {
1020 let result = self.delegate.eq_structurally_relating_aliases(
1021 param_env,
1022 lhs,
1023 rhs,
1024 self.origin_span,
1025 )?;
1026 assert_eq!(result, vec![]);
1027 Ok(())
1028 }
1029
1030 #[instrument(level = "trace", skip(self, param_env), ret)]
1031 pub(super) fn sub<T: Relate<I>>(
1032 &mut self,
1033 param_env: I::ParamEnv,
1034 sub: T,
1035 sup: T,
1036 ) -> Result<(), NoSolution> {
1037 self.relate(param_env, sub, ty::Variance::Covariant, sup)
1038 }
1039
1040 #[instrument(level = "trace", skip(self, param_env), ret)]
1041 pub(super) fn relate<T: Relate<I>>(
1042 &mut self,
1043 param_env: I::ParamEnv,
1044 lhs: T,
1045 variance: ty::Variance,
1046 rhs: T,
1047 ) -> Result<(), NoSolution> {
1048 let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
1049 for &goal in goals.iter() {
1050 let source = match goal.predicate.kind().skip_binder() {
1051 ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
1052 GoalSource::TypeRelating
1053 }
1054 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc,
1056 p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
1057 };
1058 self.add_goal(source, goal);
1059 }
1060 Ok(())
1061 }
1062
1063 #[instrument(level = "trace", skip(self, param_env), ret)]
1069 pub(super) fn eq_and_get_goals<T: Relate<I>>(
1070 &self,
1071 param_env: I::ParamEnv,
1072 lhs: T,
1073 rhs: T,
1074 ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
1075 Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
1076 }
1077
1078 pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
1079 &self,
1080 value: ty::Binder<I, T>,
1081 ) -> T {
1082 self.delegate.instantiate_binder_with_infer(value)
1083 }
1084
1085 pub(super) fn enter_forall<T: TypeFoldable<I>, U>(
1088 &mut self,
1089 value: ty::Binder<I, T>,
1090 f: impl FnOnce(&mut Self, T) -> U,
1091 ) -> U {
1092 self.delegate.enter_forall(value, |value| f(self, value))
1093 }
1094
1095 pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
1096 where
1097 T: TypeFoldable<I>,
1098 {
1099 self.delegate.resolve_vars_if_possible(value)
1100 }
1101
1102 pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
1103 if let ty::ReVar(vid) = r.kind() {
1104 self.delegate.opportunistic_resolve_lt_var(vid)
1105 } else {
1106 r
1107 }
1108 }
1109
1110 pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
1111 let args = self.delegate.fresh_args_for_item(def_id);
1112 for arg in args.iter() {
1113 self.inspect.add_var_value(arg);
1114 }
1115 args
1116 }
1117
1118 pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
1119 self.delegate.register_ty_outlives(ty, lt, self.origin_span);
1120 }
1121
1122 pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
1123 self.delegate.sub_regions(b, a, self.origin_span);
1125 }
1126
1127 pub(super) fn well_formed_goals(
1129 &self,
1130 param_env: I::ParamEnv,
1131 term: I::Term,
1132 ) -> Option<Vec<Goal<I, I::Predicate>>> {
1133 self.delegate.well_formed_goals(param_env, term)
1134 }
1135
1136 pub(super) fn trait_ref_is_knowable(
1137 &mut self,
1138 param_env: I::ParamEnv,
1139 trait_ref: ty::TraitRef<I>,
1140 ) -> Result<bool, NoSolution> {
1141 let delegate = self.delegate;
1142 let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
1143 coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty)
1144 .map(|is_knowable| is_knowable.is_ok())
1145 }
1146
1147 pub(super) fn fetch_eligible_assoc_item(
1148 &self,
1149 goal_trait_ref: ty::TraitRef<I>,
1150 trait_assoc_def_id: I::DefId,
1151 impl_def_id: I::DefId,
1152 ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
1153 self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
1154 }
1155
1156 pub(super) fn register_hidden_type_in_storage(
1157 &mut self,
1158 opaque_type_key: ty::OpaqueTypeKey<I>,
1159 hidden_ty: I::Ty,
1160 ) -> Option<I::Ty> {
1161 self.delegate.register_hidden_type_in_storage(opaque_type_key, hidden_ty, self.origin_span)
1162 }
1163
1164 pub(super) fn add_item_bounds_for_hidden_type(
1165 &mut self,
1166 opaque_def_id: I::DefId,
1167 opaque_args: I::GenericArgs,
1168 param_env: I::ParamEnv,
1169 hidden_ty: I::Ty,
1170 ) {
1171 let mut goals = Vec::new();
1172 self.delegate.add_item_bounds_for_hidden_type(
1173 opaque_def_id,
1174 opaque_args,
1175 param_env,
1176 hidden_ty,
1177 &mut goals,
1178 );
1179 self.add_goals(GoalSource::AliasWellFormed, goals);
1180 }
1181
1182 pub(super) fn probe_existing_opaque_ty(
1185 &mut self,
1186 key: ty::OpaqueTypeKey<I>,
1187 ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1188 let duplicate_entries = self.delegate.clone_duplicate_opaque_types();
1191 assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}");
1192 let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
1193 |(candidate_key, _)| {
1194 candidate_key.def_id == key.def_id
1195 && DeepRejectCtxt::relate_rigid_rigid(self.cx())
1196 .args_may_unify(candidate_key.args, key.args)
1197 },
1198 );
1199 let first = matching.next();
1200 let second = matching.next();
1201 assert_eq!(second, None);
1202 first
1203 }
1204
1205 pub(super) fn evaluate_const(
1209 &self,
1210 param_env: I::ParamEnv,
1211 uv: ty::UnevaluatedConst<I>,
1212 ) -> Option<I::Const> {
1213 self.delegate.evaluate_const(param_env, uv)
1214 }
1215
1216 pub(super) fn is_transmutable(
1217 &mut self,
1218 dst: I::Ty,
1219 src: I::Ty,
1220 assume: I::Const,
1221 ) -> Result<Certainty, NoSolution> {
1222 self.delegate.is_transmutable(dst, src, assume)
1223 }
1224}
1225
1226struct ReplaceAliasWithInfer<'me, 'a, D, I>
1241where
1242 D: SolverDelegate<Interner = I>,
1243 I: Interner,
1244{
1245 ecx: &'me mut EvalCtxt<'a, D>,
1246 param_env: I::ParamEnv,
1247 normalization_goal_source: GoalSource,
1248 cache: HashMap<I::Ty, I::Ty>,
1249}
1250
1251impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1252where
1253 D: SolverDelegate<Interner = I>,
1254 I: Interner,
1255{
1256 fn new(
1257 ecx: &'me mut EvalCtxt<'a, D>,
1258 for_goal_source: GoalSource,
1259 param_env: I::ParamEnv,
1260 ) -> Self {
1261 let step_kind = ecx.step_kind_for_source(for_goal_source);
1262 ReplaceAliasWithInfer {
1263 ecx,
1264 param_env,
1265 normalization_goal_source: GoalSource::NormalizeGoal(step_kind),
1266 cache: Default::default(),
1267 }
1268 }
1269}
1270
1271impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
1272where
1273 D: SolverDelegate<Interner = I>,
1274 I: Interner,
1275{
1276 fn cx(&self) -> I {
1277 self.ecx.cx()
1278 }
1279
1280 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1281 match ty.kind() {
1282 ty::Alias(..) if !ty.has_escaping_bound_vars() => {
1283 let infer_ty = self.ecx.next_ty_infer();
1284 let normalizes_to = ty::PredicateKind::AliasRelate(
1285 ty.into(),
1286 infer_ty.into(),
1287 ty::AliasRelationDirection::Equate,
1288 );
1289 self.ecx.add_goal(
1290 self.normalization_goal_source,
1291 Goal::new(self.cx(), self.param_env, normalizes_to),
1292 );
1293 infer_ty
1294 }
1295 _ => {
1296 if !ty.has_aliases() {
1297 ty
1298 } else if let Some(&entry) = self.cache.get(&ty) {
1299 return entry;
1300 } else {
1301 let res = ty.super_fold_with(self);
1302 assert!(self.cache.insert(ty, res).is_none());
1303 res
1304 }
1305 }
1306 }
1307 }
1308
1309 fn fold_const(&mut self, ct: I::Const) -> I::Const {
1310 match ct.kind() {
1311 ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
1312 let infer_ct = self.ecx.next_const_infer();
1313 let normalizes_to = ty::PredicateKind::AliasRelate(
1314 ct.into(),
1315 infer_ct.into(),
1316 ty::AliasRelationDirection::Equate,
1317 );
1318 self.ecx.add_goal(
1319 self.normalization_goal_source,
1320 Goal::new(self.cx(), self.param_env, normalizes_to),
1321 );
1322 infer_ct
1323 }
1324 _ => ct.super_fold_with(self),
1325 }
1326 }
1327
1328 fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
1329 if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
1330 }
1331}