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, GoalEvaluationKind, GoalSource,
26 HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult,
27};
28
29pub(super) mod canonical;
30mod probe;
31
32#[derive(Debug, Copy, Clone)]
37enum CurrentGoalKind {
38 Misc,
39 CoinductiveTrait,
44 NormalizesTo,
52}
53
54impl CurrentGoalKind {
55 fn from_query_input<I: Interner>(cx: I, input: QueryInput<I, I::Predicate>) -> CurrentGoalKind {
56 match input.goal.predicate.kind().skip_binder() {
57 ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
58 if cx.trait_is_coinductive(pred.trait_ref.def_id) {
59 CurrentGoalKind::CoinductiveTrait
60 } else {
61 CurrentGoalKind::Misc
62 }
63 }
64 ty::PredicateKind::NormalizesTo(_) => CurrentGoalKind::NormalizesTo,
65 _ => CurrentGoalKind::Misc,
66 }
67 }
68}
69
70pub struct EvalCtxt<'a, D, I = <D as SolverDelegate>::Interner>
71where
72 D: SolverDelegate<Interner = I>,
73 I: Interner,
74{
75 delegate: &'a D,
91
92 variables: I::CanonicalVars,
95
96 current_goal_kind: CurrentGoalKind,
99 pub(super) var_values: CanonicalVarValues<I>,
100
101 pub(super) max_input_universe: ty::UniverseIndex,
111 pub(super) initial_opaque_types_storage_num_entries:
114 <D::Infcx as InferCtxtLike>::OpaqueTypeStorageEntries,
115
116 pub(super) search_graph: &'a mut SearchGraph<D>,
117
118 nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>)>,
119
120 pub(super) origin_span: I::Span,
121
122 tainted: Result<(), NoSolution>,
129
130 pub(super) inspect: ProofTreeBuilder<D>,
131}
132
133#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]
134#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
135pub enum GenerateProofTree {
136 Yes,
137 No,
138}
139
140pub trait SolverDelegateEvalExt: SolverDelegate {
141 fn evaluate_root_goal(
146 &self,
147 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
148 generate_proof_tree: GenerateProofTree,
149 span: <Self::Interner as Interner>::Span,
150 ) -> (
151 Result<(HasChanged, Certainty), NoSolution>,
152 Option<inspect::GoalEvaluation<Self::Interner>>,
153 );
154
155 fn root_goal_may_hold_with_depth(
163 &self,
164 root_depth: usize,
165 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
166 ) -> bool;
167
168 fn evaluate_root_goal_raw(
171 &self,
172 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
173 generate_proof_tree: GenerateProofTree,
174 ) -> (
175 Result<(NestedNormalizationGoals<Self::Interner>, HasChanged, Certainty), NoSolution>,
176 Option<inspect::GoalEvaluation<Self::Interner>>,
177 );
178}
179
180impl<D, I> SolverDelegateEvalExt for D
181where
182 D: SolverDelegate<Interner = I>,
183 I: Interner,
184{
185 #[instrument(level = "debug", skip(self))]
186 fn evaluate_root_goal(
187 &self,
188 goal: Goal<I, I::Predicate>,
189 generate_proof_tree: GenerateProofTree,
190 span: I::Span,
191 ) -> (Result<(HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
192 EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| {
193 ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
194 })
195 }
196
197 fn root_goal_may_hold_with_depth(
198 &self,
199 root_depth: usize,
200 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
201 ) -> bool {
202 self.probe(|| {
203 EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| {
204 ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
205 })
206 .0
207 })
208 .is_ok()
209 }
210
211 #[instrument(level = "debug", skip(self))]
212 fn evaluate_root_goal_raw(
213 &self,
214 goal: Goal<I, I::Predicate>,
215 generate_proof_tree: GenerateProofTree,
216 ) -> (
217 Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution>,
218 Option<inspect::GoalEvaluation<I>>,
219 ) {
220 EvalCtxt::enter_root(
221 self,
222 self.cx().recursion_limit(),
223 generate_proof_tree,
224 I::Span::dummy(),
225 |ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal),
226 )
227 }
228}
229
230impl<'a, D, I> EvalCtxt<'a, D>
231where
232 D: SolverDelegate<Interner = I>,
233 I: Interner,
234{
235 pub(super) fn typing_mode(&self) -> TypingMode<I> {
236 self.delegate.typing_mode()
237 }
238
239 pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
248 match source {
249 GoalSource::Misc => PathKind::Unknown,
257 GoalSource::NormalizeGoal(path_kind) => path_kind,
258 GoalSource::ImplWhereBound => match self.current_goal_kind {
259 CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive,
262 CurrentGoalKind::NormalizesTo => PathKind::Inductive,
270 CurrentGoalKind::Misc => PathKind::Unknown,
274 },
275 GoalSource::TypeRelating => PathKind::Inductive,
279 GoalSource::InstantiateHigherRanked => PathKind::Inductive,
282 GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
286 }
287 }
288
289 pub(super) fn enter_root<R>(
293 delegate: &D,
294 root_depth: usize,
295 generate_proof_tree: GenerateProofTree,
296 origin_span: I::Span,
297 f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
298 ) -> (R, Option<inspect::GoalEvaluation<I>>) {
299 let mut search_graph = SearchGraph::new(root_depth);
300
301 let mut ecx = EvalCtxt {
302 delegate,
303 search_graph: &mut search_graph,
304 nested_goals: Default::default(),
305 inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree),
306
307 max_input_universe: ty::UniverseIndex::ROOT,
310 initial_opaque_types_storage_num_entries: Default::default(),
311 variables: Default::default(),
312 var_values: CanonicalVarValues::dummy(),
313 current_goal_kind: CurrentGoalKind::Misc,
314 origin_span,
315 tainted: Ok(()),
316 };
317 let result = f(&mut ecx);
318
319 let proof_tree = ecx.inspect.finalize();
320 assert!(
321 ecx.nested_goals.is_empty(),
322 "root `EvalCtxt` should not have any goals added to it"
323 );
324
325 assert!(search_graph.is_empty());
326 (result, proof_tree)
327 }
328
329 fn enter_canonical<R>(
338 cx: I,
339 search_graph: &'a mut SearchGraph<D>,
340 canonical_input: CanonicalInput<I>,
341 canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
342 f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
343 ) -> R {
344 let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input);
345
346 for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
347 let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy());
348 if let Some(prev) = prev {
360 debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
361 }
362 }
363
364 let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries();
365 let mut ecx = EvalCtxt {
366 delegate,
367 variables: canonical_input.canonical.variables,
368 var_values,
369 current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
370 max_input_universe: canonical_input.canonical.max_universe,
371 initial_opaque_types_storage_num_entries,
372 search_graph,
373 nested_goals: Default::default(),
374 origin_span: I::Span::dummy(),
375 tainted: Ok(()),
376 inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
377 };
378
379 let result = f(&mut ecx, input.goal);
380 ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe);
381 canonical_goal_evaluation.goal_evaluation_step(ecx.inspect);
382
383 delegate.reset_opaque_types();
389
390 result
391 }
392
393 #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
403 fn evaluate_canonical_goal(
404 cx: I,
405 search_graph: &'a mut SearchGraph<D>,
406 canonical_input: CanonicalInput<I>,
407 step_kind_from_parent: PathKind,
408 goal_evaluation: &mut ProofTreeBuilder<D>,
409 ) -> QueryResult<I> {
410 let mut canonical_goal_evaluation =
411 goal_evaluation.new_canonical_goal_evaluation(canonical_input);
412
413 let result = ensure_sufficient_stack(|| {
417 search_graph.with_new_goal(
418 cx,
419 canonical_input,
420 step_kind_from_parent,
421 &mut canonical_goal_evaluation,
422 |search_graph, canonical_goal_evaluation| {
423 EvalCtxt::enter_canonical(
424 cx,
425 search_graph,
426 canonical_input,
427 canonical_goal_evaluation,
428 |ecx, goal| {
429 let result = ecx.compute_goal(goal);
430 ecx.inspect.query_result(result);
431 result
432 },
433 )
434 },
435 )
436 });
437
438 canonical_goal_evaluation.query_result(result);
439 goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
440 result
441 }
442
443 fn evaluate_goal(
446 &mut self,
447 goal_evaluation_kind: GoalEvaluationKind,
448 source: GoalSource,
449 goal: Goal<I, I::Predicate>,
450 ) -> Result<(HasChanged, Certainty), NoSolution> {
451 let (normalization_nested_goals, has_changed, certainty) =
452 self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
453 assert!(normalization_nested_goals.is_empty());
454 Ok((has_changed, certainty))
455 }
456
457 pub(super) fn evaluate_goal_raw(
465 &mut self,
466 goal_evaluation_kind: GoalEvaluationKind,
467 source: GoalSource,
468 goal: Goal<I, I::Predicate>,
469 ) -> Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution> {
470 let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
471 let mut goal_evaluation =
472 self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
473 let canonical_response = EvalCtxt::evaluate_canonical_goal(
474 self.cx(),
475 self.search_graph,
476 canonical_goal,
477 self.step_kind_for_source(source),
478 &mut goal_evaluation,
479 );
480 let response = match canonical_response {
481 Err(e) => {
482 self.inspect.goal_evaluation(goal_evaluation);
483 return Err(e);
484 }
485 Ok(response) => response,
486 };
487
488 let has_changed =
489 if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
490
491 let (normalization_nested_goals, certainty) =
492 self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
493 self.inspect.goal_evaluation(goal_evaluation);
494
495 Ok((normalization_nested_goals, has_changed, certainty))
506 }
507
508 fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
509 let Goal { param_env, predicate } = goal;
510 let kind = predicate.kind();
511 if let Some(kind) = kind.no_bound_vars() {
512 match kind {
513 ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
514 self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)
515 }
516 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
517 self.compute_host_effect_goal(Goal { param_env, predicate })
518 }
519 ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
520 self.compute_projection_goal(Goal { param_env, predicate })
521 }
522 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
523 self.compute_type_outlives_goal(Goal { param_env, predicate })
524 }
525 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
526 self.compute_region_outlives_goal(Goal { param_env, predicate })
527 }
528 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
529 self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
530 }
531 ty::PredicateKind::Subtype(predicate) => {
532 self.compute_subtype_goal(Goal { param_env, predicate })
533 }
534 ty::PredicateKind::Coerce(predicate) => {
535 self.compute_coerce_goal(Goal { param_env, predicate })
536 }
537 ty::PredicateKind::DynCompatible(trait_def_id) => {
538 self.compute_dyn_compatible_goal(trait_def_id)
539 }
540 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
541 self.compute_well_formed_goal(Goal { param_env, predicate: term })
542 }
543 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
544 self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
545 }
546 ty::PredicateKind::ConstEquate(_, _) => {
547 panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
548 }
549 ty::PredicateKind::NormalizesTo(predicate) => {
550 self.compute_normalizes_to_goal(Goal { param_env, predicate })
551 }
552 ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
553 .compute_alias_relate_goal(Goal {
554 param_env,
555 predicate: (lhs, rhs, direction),
556 }),
557 ty::PredicateKind::Ambiguous => {
558 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
559 }
560 }
561 } else {
562 self.enter_forall(kind, |ecx, kind| {
563 let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
564 ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
565 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
566 })
567 }
568 }
569
570 #[instrument(level = "trace", skip(self))]
573 pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
574 let mut response = Ok(Certainty::overflow(false));
575 for _ in 0..FIXPOINT_STEP_LIMIT {
576 match self.evaluate_added_goals_step() {
579 Ok(Some(cert)) => {
580 response = Ok(cert);
581 break;
582 }
583 Ok(None) => {}
584 Err(NoSolution) => {
585 response = Err(NoSolution);
586 break;
587 }
588 }
589 }
590
591 if response.is_err() {
592 self.tainted = Err(NoSolution);
593 }
594
595 response
596 }
597
598 fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> {
602 let cx = self.cx();
603 let mut unchanged_certainty = Some(Certainty::Yes);
605 for (source, goal) in mem::take(&mut self.nested_goals) {
606 if let Some(pred) = goal.predicate.as_normalizes_to() {
617 let pred = pred.no_bound_vars().unwrap();
619 let unconstrained_rhs = self.next_term_infer_of_kind(pred.term);
622 let unconstrained_goal =
623 goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs });
624
625 let (NestedNormalizationGoals(nested_goals), _, certainty) =
626 self.evaluate_goal_raw(GoalEvaluationKind::Nested, source, unconstrained_goal)?;
627 trace!(?nested_goals);
629 self.nested_goals.extend(nested_goals);
630
631 self.eq_structurally_relating_aliases(
646 goal.param_env,
647 pred.term,
648 unconstrained_rhs,
649 )?;
650
651 let with_resolved_vars = self.resolve_vars_if_possible(goal);
656 if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias {
657 unchanged_certainty = None;
658 }
659
660 match certainty {
661 Certainty::Yes => {}
662 Certainty::Maybe(_) => {
663 self.nested_goals.push((source, with_resolved_vars));
664 unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
665 }
666 }
667 } else {
668 let (has_changed, certainty) =
669 self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?;
670 if has_changed == HasChanged::Yes {
671 unchanged_certainty = None;
672 }
673
674 match certainty {
675 Certainty::Yes => {}
676 Certainty::Maybe(_) => {
677 self.nested_goals.push((source, goal));
678 unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
679 }
680 }
681 }
682 }
683
684 Ok(unchanged_certainty)
685 }
686
687 pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) {
689 self.inspect.record_impl_args(self.delegate, self.max_input_universe, impl_args)
690 }
691
692 pub(super) fn cx(&self) -> I {
693 self.delegate.cx()
694 }
695
696 #[instrument(level = "debug", skip(self))]
697 pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
698 goal.predicate =
699 goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env));
700 self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
701 self.nested_goals.push((source, goal));
702 }
703
704 #[instrument(level = "trace", skip(self, goals))]
705 pub(super) fn add_goals(
706 &mut self,
707 source: GoalSource,
708 goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
709 ) {
710 for goal in goals {
711 self.add_goal(source, goal);
712 }
713 }
714
715 pub(super) fn next_region_var(&mut self) -> I::Region {
716 let region = self.delegate.next_region_infer();
717 self.inspect.add_var_value(region);
718 region
719 }
720
721 pub(super) fn next_ty_infer(&mut self) -> I::Ty {
722 let ty = self.delegate.next_ty_infer();
723 self.inspect.add_var_value(ty);
724 ty
725 }
726
727 pub(super) fn next_const_infer(&mut self) -> I::Const {
728 let ct = self.delegate.next_const_infer();
729 self.inspect.add_var_value(ct);
730 ct
731 }
732
733 pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
736 match kind.kind() {
737 ty::TermKind::Ty(_) => self.next_ty_infer().into(),
738 ty::TermKind::Const(_) => self.next_const_infer().into(),
739 }
740 }
741
742 #[instrument(level = "trace", skip(self), ret)]
747 pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
748 let universe_of_term = match goal.predicate.term.kind() {
749 ty::TermKind::Ty(ty) => {
750 if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
751 self.delegate.universe_of_ty(vid).unwrap()
752 } else {
753 return false;
754 }
755 }
756 ty::TermKind::Const(ct) => {
757 if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
758 self.delegate.universe_of_ct(vid).unwrap()
759 } else {
760 return false;
761 }
762 }
763 };
764
765 struct ContainsTermOrNotNameable<'a, D: SolverDelegate<Interner = I>, I: Interner> {
766 term: I::Term,
767 universe_of_term: ty::UniverseIndex,
768 delegate: &'a D,
769 cache: HashSet<I::Ty>,
770 }
771
772 impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
773 fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
774 if self.universe_of_term.can_name(universe) {
775 ControlFlow::Continue(())
776 } else {
777 ControlFlow::Break(())
778 }
779 }
780 }
781
782 impl<D: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
783 for ContainsTermOrNotNameable<'_, D, I>
784 {
785 type Result = ControlFlow<()>;
786 fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
787 if self.cache.contains(&t) {
788 return ControlFlow::Continue(());
789 }
790
791 match t.kind() {
792 ty::Infer(ty::TyVar(vid)) => {
793 if let ty::TermKind::Ty(term) = self.term.kind() {
794 if let ty::Infer(ty::TyVar(term_vid)) = term.kind() {
795 if self.delegate.root_ty_var(vid)
796 == self.delegate.root_ty_var(term_vid)
797 {
798 return ControlFlow::Break(());
799 }
800 }
801 }
802
803 self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
804 }
805 ty::Placeholder(p) => self.check_nameable(p.universe())?,
806 _ => {
807 if t.has_non_region_infer() || t.has_placeholders() {
808 t.super_visit_with(self)?
809 }
810 }
811 }
812
813 assert!(self.cache.insert(t));
814 ControlFlow::Continue(())
815 }
816
817 fn visit_const(&mut self, c: I::Const) -> Self::Result {
818 match c.kind() {
819 ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
820 if let ty::TermKind::Const(term) = self.term.kind() {
821 if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
822 {
823 if self.delegate.root_const_var(vid)
824 == self.delegate.root_const_var(term_vid)
825 {
826 return ControlFlow::Break(());
827 }
828 }
829 }
830
831 self.check_nameable(self.delegate.universe_of_ct(vid).unwrap())
832 }
833 ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
834 _ => {
835 if c.has_non_region_infer() || c.has_placeholders() {
836 c.super_visit_with(self)
837 } else {
838 ControlFlow::Continue(())
839 }
840 }
841 }
842 }
843 }
844
845 let mut visitor = ContainsTermOrNotNameable {
846 delegate: self.delegate,
847 universe_of_term,
848 term: goal.predicate.term,
849 cache: Default::default(),
850 };
851 goal.predicate.alias.visit_with(&mut visitor).is_continue()
852 && goal.param_env.visit_with(&mut visitor).is_continue()
853 }
854
855 #[instrument(level = "trace", skip(self, param_env), ret)]
856 pub(super) fn eq<T: Relate<I>>(
857 &mut self,
858 param_env: I::ParamEnv,
859 lhs: T,
860 rhs: T,
861 ) -> Result<(), NoSolution> {
862 self.relate(param_env, lhs, ty::Variance::Invariant, rhs)
863 }
864
865 #[instrument(level = "trace", skip(self, param_env), ret)]
871 pub(super) fn relate_rigid_alias_non_alias(
872 &mut self,
873 param_env: I::ParamEnv,
874 alias: ty::AliasTerm<I>,
875 variance: ty::Variance,
876 term: I::Term,
877 ) -> Result<(), NoSolution> {
878 if term.is_infer() {
881 let cx = self.cx();
882 let identity_args = self.fresh_args_for_item(alias.def_id);
891 let rigid_ctor = ty::AliasTerm::new_from_args(cx, alias.def_id, identity_args);
892 let ctor_term = rigid_ctor.to_term(cx);
893 let obligations = self.delegate.eq_structurally_relating_aliases(
894 param_env,
895 term,
896 ctor_term,
897 self.origin_span,
898 )?;
899 debug_assert!(obligations.is_empty());
900 self.relate(param_env, alias, variance, rigid_ctor)
901 } else {
902 Err(NoSolution)
903 }
904 }
905
906 #[instrument(level = "trace", skip(self, param_env), ret)]
910 pub(super) fn eq_structurally_relating_aliases<T: Relate<I>>(
911 &mut self,
912 param_env: I::ParamEnv,
913 lhs: T,
914 rhs: T,
915 ) -> Result<(), NoSolution> {
916 let result = self.delegate.eq_structurally_relating_aliases(
917 param_env,
918 lhs,
919 rhs,
920 self.origin_span,
921 )?;
922 assert_eq!(result, vec![]);
923 Ok(())
924 }
925
926 #[instrument(level = "trace", skip(self, param_env), ret)]
927 pub(super) fn sub<T: Relate<I>>(
928 &mut self,
929 param_env: I::ParamEnv,
930 sub: T,
931 sup: T,
932 ) -> Result<(), NoSolution> {
933 self.relate(param_env, sub, ty::Variance::Covariant, sup)
934 }
935
936 #[instrument(level = "trace", skip(self, param_env), ret)]
937 pub(super) fn relate<T: Relate<I>>(
938 &mut self,
939 param_env: I::ParamEnv,
940 lhs: T,
941 variance: ty::Variance,
942 rhs: T,
943 ) -> Result<(), NoSolution> {
944 let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
945 for &goal in goals.iter() {
946 let source = match goal.predicate.kind().skip_binder() {
947 ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
948 GoalSource::TypeRelating
949 }
950 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc,
952 p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
953 };
954 self.add_goal(source, goal);
955 }
956 Ok(())
957 }
958
959 #[instrument(level = "trace", skip(self, param_env), ret)]
965 pub(super) fn eq_and_get_goals<T: Relate<I>>(
966 &self,
967 param_env: I::ParamEnv,
968 lhs: T,
969 rhs: T,
970 ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
971 Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
972 }
973
974 pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
975 &self,
976 value: ty::Binder<I, T>,
977 ) -> T {
978 self.delegate.instantiate_binder_with_infer(value)
979 }
980
981 pub(super) fn enter_forall<T: TypeFoldable<I>, U>(
984 &mut self,
985 value: ty::Binder<I, T>,
986 f: impl FnOnce(&mut Self, T) -> U,
987 ) -> U {
988 self.delegate.enter_forall(value, |value| f(self, value))
989 }
990
991 pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
992 where
993 T: TypeFoldable<I>,
994 {
995 self.delegate.resolve_vars_if_possible(value)
996 }
997
998 pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
999 if let ty::ReVar(vid) = r.kind() {
1000 self.delegate.opportunistic_resolve_lt_var(vid)
1001 } else {
1002 r
1003 }
1004 }
1005
1006 pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
1007 let args = self.delegate.fresh_args_for_item(def_id);
1008 for arg in args.iter() {
1009 self.inspect.add_var_value(arg);
1010 }
1011 args
1012 }
1013
1014 pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
1015 self.delegate.register_ty_outlives(ty, lt, self.origin_span);
1016 }
1017
1018 pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
1019 self.delegate.sub_regions(b, a, self.origin_span);
1021 }
1022
1023 pub(super) fn well_formed_goals(
1025 &self,
1026 param_env: I::ParamEnv,
1027 term: I::Term,
1028 ) -> Option<Vec<Goal<I, I::Predicate>>> {
1029 self.delegate.well_formed_goals(param_env, term)
1030 }
1031
1032 pub(super) fn trait_ref_is_knowable(
1033 &mut self,
1034 param_env: I::ParamEnv,
1035 trait_ref: ty::TraitRef<I>,
1036 ) -> Result<bool, NoSolution> {
1037 let delegate = self.delegate;
1038 let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
1039 coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty)
1040 .map(|is_knowable| is_knowable.is_ok())
1041 }
1042
1043 pub(super) fn fetch_eligible_assoc_item(
1044 &self,
1045 goal_trait_ref: ty::TraitRef<I>,
1046 trait_assoc_def_id: I::DefId,
1047 impl_def_id: I::DefId,
1048 ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
1049 self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
1050 }
1051
1052 pub(super) fn register_hidden_type_in_storage(
1053 &mut self,
1054 opaque_type_key: ty::OpaqueTypeKey<I>,
1055 hidden_ty: I::Ty,
1056 ) -> Option<I::Ty> {
1057 self.delegate.register_hidden_type_in_storage(opaque_type_key, hidden_ty, self.origin_span)
1058 }
1059
1060 pub(super) fn add_item_bounds_for_hidden_type(
1061 &mut self,
1062 opaque_def_id: I::DefId,
1063 opaque_args: I::GenericArgs,
1064 param_env: I::ParamEnv,
1065 hidden_ty: I::Ty,
1066 ) {
1067 let mut goals = Vec::new();
1068 self.delegate.add_item_bounds_for_hidden_type(
1069 opaque_def_id,
1070 opaque_args,
1071 param_env,
1072 hidden_ty,
1073 &mut goals,
1074 );
1075 self.add_goals(GoalSource::AliasWellFormed, goals);
1076 }
1077
1078 pub(super) fn probe_existing_opaque_ty(
1081 &mut self,
1082 key: ty::OpaqueTypeKey<I>,
1083 ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1084 let duplicate_entries = self.delegate.clone_duplicate_opaque_types();
1087 assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}");
1088 let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
1089 |(candidate_key, _)| {
1090 candidate_key.def_id == key.def_id
1091 && DeepRejectCtxt::relate_rigid_rigid(self.cx())
1092 .args_may_unify(candidate_key.args, key.args)
1093 },
1094 );
1095 let first = matching.next();
1096 let second = matching.next();
1097 assert_eq!(second, None);
1098 first
1099 }
1100
1101 pub(super) fn evaluate_const(
1105 &self,
1106 param_env: I::ParamEnv,
1107 uv: ty::UnevaluatedConst<I>,
1108 ) -> Option<I::Const> {
1109 self.delegate.evaluate_const(param_env, uv)
1110 }
1111
1112 pub(super) fn is_transmutable(
1113 &mut self,
1114 dst: I::Ty,
1115 src: I::Ty,
1116 assume: I::Const,
1117 ) -> Result<Certainty, NoSolution> {
1118 self.delegate.is_transmutable(dst, src, assume)
1119 }
1120}
1121
1122struct ReplaceAliasWithInfer<'me, 'a, D, I>
1137where
1138 D: SolverDelegate<Interner = I>,
1139 I: Interner,
1140{
1141 ecx: &'me mut EvalCtxt<'a, D>,
1142 param_env: I::ParamEnv,
1143 normalization_goal_source: GoalSource,
1144 cache: HashMap<I::Ty, I::Ty>,
1145}
1146
1147impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1148where
1149 D: SolverDelegate<Interner = I>,
1150 I: Interner,
1151{
1152 fn new(
1153 ecx: &'me mut EvalCtxt<'a, D>,
1154 for_goal_source: GoalSource,
1155 param_env: I::ParamEnv,
1156 ) -> Self {
1157 let step_kind = ecx.step_kind_for_source(for_goal_source);
1158 ReplaceAliasWithInfer {
1159 ecx,
1160 param_env,
1161 normalization_goal_source: GoalSource::NormalizeGoal(step_kind),
1162 cache: Default::default(),
1163 }
1164 }
1165}
1166
1167impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
1168where
1169 D: SolverDelegate<Interner = I>,
1170 I: Interner,
1171{
1172 fn cx(&self) -> I {
1173 self.ecx.cx()
1174 }
1175
1176 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1177 match ty.kind() {
1178 ty::Alias(..) if !ty.has_escaping_bound_vars() => {
1179 let infer_ty = self.ecx.next_ty_infer();
1180 let normalizes_to = ty::PredicateKind::AliasRelate(
1181 ty.into(),
1182 infer_ty.into(),
1183 ty::AliasRelationDirection::Equate,
1184 );
1185 self.ecx.add_goal(
1186 self.normalization_goal_source,
1187 Goal::new(self.cx(), self.param_env, normalizes_to),
1188 );
1189 infer_ty
1190 }
1191 _ => {
1192 if !ty.has_aliases() {
1193 ty
1194 } else if let Some(&entry) = self.cache.get(&ty) {
1195 return entry;
1196 } else {
1197 let res = ty.super_fold_with(self);
1198 assert!(self.cache.insert(ty, res).is_none());
1199 res
1200 }
1201 }
1202 }
1203 }
1204
1205 fn fold_const(&mut self, ct: I::Const) -> I::Const {
1206 match ct.kind() {
1207 ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
1208 let infer_ct = self.ecx.next_const_infer();
1209 let normalizes_to = ty::PredicateKind::AliasRelate(
1210 ct.into(),
1211 infer_ct.into(),
1212 ty::AliasRelationDirection::Equate,
1213 );
1214 self.ecx.add_goal(
1215 self.normalization_goal_source,
1216 Goal::new(self.cx(), self.param_env, normalizes_to),
1217 );
1218 infer_ct
1219 }
1220 _ => ct.super_fold_with(self),
1221 }
1222 }
1223
1224 fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
1225 if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
1226 }
1227}