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