1use std::ops::ControlFlow;
2
3use derive_where::derive_where;
4#[cfg(feature = "nightly")]
5use rustc_macros::{Decodable_NoContext, Encodable_NoContext, 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 rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
18use tracing::{instrument, trace};
19
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, PredefinedOpaquesData, 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::CanonicalVars,
96
97 current_goal_kind: CurrentGoalKind,
100 pub(super) var_values: CanonicalVarValues<I>,
101
102 predefined_opaques_in_body: I::PredefinedOpaques,
103
104 pub(super) max_input_universe: ty::UniverseIndex,
114
115 pub(super) search_graph: &'a mut SearchGraph<D>,
116
117 nested_goals: NestedGoals<I>,
118
119 pub(super) origin_span: I::Span,
120
121 tainted: Result<(), NoSolution>,
128
129 pub(super) inspect: ProofTreeBuilder<D>,
130}
131
132#[derive_where(Clone, Debug, Default; I: Interner)]
133#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
134#[cfg_attr(
135 feature = "nightly",
136 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
137)]
138struct NestedGoals<I: Interner> {
139 pub normalizes_to_goals: Vec<Goal<I, ty::NormalizesTo<I>>>,
150 pub goals: Vec<(GoalSource, Goal<I, I::Predicate>)>,
152}
153
154impl<I: Interner> NestedGoals<I> {
155 fn new() -> Self {
156 Self { normalizes_to_goals: Vec::new(), goals: Vec::new() }
157 }
158
159 fn is_empty(&self) -> bool {
160 self.normalizes_to_goals.is_empty() && self.goals.is_empty()
161 }
162}
163
164#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]
165#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
166pub enum GenerateProofTree {
167 Yes,
168 No,
169}
170
171pub trait SolverDelegateEvalExt: SolverDelegate {
172 fn evaluate_root_goal(
177 &self,
178 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
179 generate_proof_tree: GenerateProofTree,
180 span: <Self::Interner as Interner>::Span,
181 ) -> (
182 Result<(HasChanged, Certainty), NoSolution>,
183 Option<inspect::GoalEvaluation<Self::Interner>>,
184 );
185
186 fn root_goal_may_hold_with_depth(
194 &self,
195 root_depth: usize,
196 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
197 ) -> bool;
198
199 fn evaluate_root_goal_raw(
202 &self,
203 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
204 generate_proof_tree: GenerateProofTree,
205 ) -> (
206 Result<(NestedNormalizationGoals<Self::Interner>, HasChanged, Certainty), NoSolution>,
207 Option<inspect::GoalEvaluation<Self::Interner>>,
208 );
209}
210
211impl<D, I> SolverDelegateEvalExt for D
212where
213 D: SolverDelegate<Interner = I>,
214 I: Interner,
215{
216 #[instrument(level = "debug", skip(self))]
217 fn evaluate_root_goal(
218 &self,
219 goal: Goal<I, I::Predicate>,
220 generate_proof_tree: GenerateProofTree,
221 span: I::Span,
222 ) -> (Result<(HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
223 EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| {
224 ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
225 })
226 }
227
228 fn root_goal_may_hold_with_depth(
229 &self,
230 root_depth: usize,
231 goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
232 ) -> bool {
233 self.probe(|| {
234 EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| {
235 ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
236 })
237 .0
238 })
239 .is_ok()
240 }
241
242 #[instrument(level = "debug", skip(self))]
243 fn evaluate_root_goal_raw(
244 &self,
245 goal: Goal<I, I::Predicate>,
246 generate_proof_tree: GenerateProofTree,
247 ) -> (
248 Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution>,
249 Option<inspect::GoalEvaluation<I>>,
250 ) {
251 EvalCtxt::enter_root(
252 self,
253 self.cx().recursion_limit(),
254 generate_proof_tree,
255 I::Span::dummy(),
256 |ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal),
257 )
258 }
259}
260
261impl<'a, D, I> EvalCtxt<'a, D>
262where
263 D: SolverDelegate<Interner = I>,
264 I: Interner,
265{
266 pub(super) fn typing_mode(&self) -> TypingMode<I> {
267 self.delegate.typing_mode()
268 }
269
270 pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
279 match source {
280 GoalSource::Misc => PathKind::Unknown,
288 GoalSource::NormalizeGoal(path_kind) => path_kind,
289 GoalSource::ImplWhereBound => {
290 if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind {
296 PathKind::Coinductive
297 } else {
298 PathKind::Unknown
299 }
300 }
301 GoalSource::TypeRelating => PathKind::Inductive,
305 GoalSource::InstantiateHigherRanked => PathKind::Inductive,
308 GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
312 }
313 }
314
315 pub(super) fn enter_root<R>(
319 delegate: &D,
320 root_depth: usize,
321 generate_proof_tree: GenerateProofTree,
322 origin_span: I::Span,
323 f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
324 ) -> (R, Option<inspect::GoalEvaluation<I>>) {
325 let mut search_graph = SearchGraph::new(root_depth);
326
327 let mut ecx = EvalCtxt {
328 delegate,
329 search_graph: &mut search_graph,
330 nested_goals: NestedGoals::new(),
331 inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree),
332
333 predefined_opaques_in_body: delegate
336 .cx()
337 .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
338 max_input_universe: ty::UniverseIndex::ROOT,
339 variables: Default::default(),
340 var_values: CanonicalVarValues::dummy(),
341 current_goal_kind: CurrentGoalKind::Misc,
342 origin_span,
343 tainted: Ok(()),
344 };
345 let result = f(&mut ecx);
346
347 let proof_tree = ecx.inspect.finalize();
348 assert!(
349 ecx.nested_goals.is_empty(),
350 "root `EvalCtxt` should not have any goals added to it"
351 );
352
353 assert!(search_graph.is_empty());
354 (result, proof_tree)
355 }
356
357 fn enter_canonical<R>(
366 cx: I,
367 search_graph: &'a mut SearchGraph<D>,
368 canonical_input: CanonicalInput<I>,
369 canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
370 f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
371 ) -> R {
372 let (ref delegate, input, var_values) =
373 SolverDelegate::build_with_canonical(cx, &canonical_input);
374
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 predefined_opaques_in_body: input.predefined_opaques_in_body,
381 max_input_universe: canonical_input.canonical.max_universe,
382 search_graph,
383 nested_goals: NestedGoals::new(),
384 origin_span: I::Span::dummy(),
385 tainted: Ok(()),
386 inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
387 };
388
389 for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
390 ecx.delegate.inject_new_hidden_type_unchecked(key, ty, ecx.origin_span);
391 }
392
393 if !ecx.nested_goals.is_empty() {
394 panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals);
395 }
396
397 let result = f(&mut ecx, input.goal);
398 ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe);
399 canonical_goal_evaluation.goal_evaluation_step(ecx.inspect);
400
401 delegate.reset_opaque_types();
407
408 result
409 }
410
411 #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
421 fn evaluate_canonical_goal(
422 cx: I,
423 search_graph: &'a mut SearchGraph<D>,
424 canonical_input: CanonicalInput<I>,
425 step_kind_from_parent: PathKind,
426 goal_evaluation: &mut ProofTreeBuilder<D>,
427 ) -> QueryResult<I> {
428 let mut canonical_goal_evaluation =
429 goal_evaluation.new_canonical_goal_evaluation(canonical_input);
430
431 let result = ensure_sufficient_stack(|| {
435 search_graph.with_new_goal(
436 cx,
437 canonical_input,
438 step_kind_from_parent,
439 &mut canonical_goal_evaluation,
440 |search_graph, canonical_goal_evaluation| {
441 EvalCtxt::enter_canonical(
442 cx,
443 search_graph,
444 canonical_input,
445 canonical_goal_evaluation,
446 |ecx, goal| {
447 let result = ecx.compute_goal(goal);
448 ecx.inspect.query_result(result);
449 result
450 },
451 )
452 },
453 )
454 });
455
456 canonical_goal_evaluation.query_result(result);
457 goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
458 result
459 }
460
461 fn evaluate_goal(
464 &mut self,
465 goal_evaluation_kind: GoalEvaluationKind,
466 source: GoalSource,
467 goal: Goal<I, I::Predicate>,
468 ) -> Result<(HasChanged, Certainty), NoSolution> {
469 let (normalization_nested_goals, has_changed, certainty) =
470 self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
471 assert!(normalization_nested_goals.is_empty());
472 Ok((has_changed, certainty))
473 }
474
475 pub(super) fn evaluate_goal_raw(
483 &mut self,
484 goal_evaluation_kind: GoalEvaluationKind,
485 source: GoalSource,
486 goal: Goal<I, I::Predicate>,
487 ) -> Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution> {
488 let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
489 let mut goal_evaluation =
490 self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
491 let canonical_response = EvalCtxt::evaluate_canonical_goal(
492 self.cx(),
493 self.search_graph,
494 canonical_goal,
495 self.step_kind_for_source(source),
496 &mut goal_evaluation,
497 );
498 let response = match canonical_response {
499 Err(e) => {
500 self.inspect.goal_evaluation(goal_evaluation);
501 return Err(e);
502 }
503 Ok(response) => response,
504 };
505
506 let has_changed = if !response.value.var_values.is_identity_modulo_regions()
507 || !response.value.external_constraints.opaque_types.is_empty()
508 {
509 HasChanged::Yes
510 } else {
511 HasChanged::No
512 };
513
514 let (normalization_nested_goals, certainty) =
515 self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
516 self.inspect.goal_evaluation(goal_evaluation);
517
518 Ok((normalization_nested_goals, has_changed, certainty))
529 }
530
531 fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
532 let Goal { param_env, predicate } = goal;
533 let kind = predicate.kind();
534 if let Some(kind) = kind.no_bound_vars() {
535 match kind {
536 ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
537 self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)
538 }
539 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
540 self.compute_host_effect_goal(Goal { param_env, predicate })
541 }
542 ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
543 self.compute_projection_goal(Goal { param_env, predicate })
544 }
545 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
546 self.compute_type_outlives_goal(Goal { param_env, predicate })
547 }
548 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
549 self.compute_region_outlives_goal(Goal { param_env, predicate })
550 }
551 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
552 self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
553 }
554 ty::PredicateKind::Subtype(predicate) => {
555 self.compute_subtype_goal(Goal { param_env, predicate })
556 }
557 ty::PredicateKind::Coerce(predicate) => {
558 self.compute_coerce_goal(Goal { param_env, predicate })
559 }
560 ty::PredicateKind::DynCompatible(trait_def_id) => {
561 self.compute_dyn_compatible_goal(trait_def_id)
562 }
563 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
564 self.compute_well_formed_goal(Goal { param_env, predicate: arg })
565 }
566 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
567 self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
568 }
569 ty::PredicateKind::ConstEquate(_, _) => {
570 panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
571 }
572 ty::PredicateKind::NormalizesTo(predicate) => {
573 self.compute_normalizes_to_goal(Goal { param_env, predicate })
574 }
575 ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
576 .compute_alias_relate_goal(Goal {
577 param_env,
578 predicate: (lhs, rhs, direction),
579 }),
580 ty::PredicateKind::Ambiguous => {
581 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
582 }
583 }
584 } else {
585 self.enter_forall(kind, |ecx, kind| {
586 let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
587 ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
588 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
589 })
590 }
591 }
592
593 #[instrument(level = "trace", skip(self))]
596 pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
597 let mut response = Ok(Certainty::overflow(false));
598 for _ in 0..FIXPOINT_STEP_LIMIT {
599 match self.evaluate_added_goals_step() {
602 Ok(Some(cert)) => {
603 response = Ok(cert);
604 break;
605 }
606 Ok(None) => {}
607 Err(NoSolution) => {
608 response = Err(NoSolution);
609 break;
610 }
611 }
612 }
613
614 if response.is_err() {
615 self.tainted = Err(NoSolution);
616 }
617
618 response
619 }
620
621 fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> {
625 let cx = self.cx();
626 let mut goals = core::mem::take(&mut self.nested_goals);
627
628 let mut unchanged_certainty = Some(Certainty::Yes);
630 for goal in goals.normalizes_to_goals {
631 let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term);
634 let unconstrained_goal = goal.with(
635 cx,
636 ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs },
637 );
638
639 let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw(
640 GoalEvaluationKind::Nested,
641 GoalSource::TypeRelating,
642 unconstrained_goal,
643 )?;
644 trace!(?nested_goals);
646 goals.goals.extend(nested_goals);
647
648 self.eq_structurally_relating_aliases(
663 goal.param_env,
664 goal.predicate.term,
665 unconstrained_rhs,
666 )?;
667
668 let with_resolved_vars = self.resolve_vars_if_possible(goal);
673 if goal.predicate.alias != with_resolved_vars.predicate.alias {
674 unchanged_certainty = None;
675 }
676
677 match certainty {
678 Certainty::Yes => {}
679 Certainty::Maybe(_) => {
680 self.nested_goals.normalizes_to_goals.push(with_resolved_vars);
681 unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
682 }
683 }
684 }
685
686 for (source, goal) in goals.goals {
687 let (has_changed, certainty) =
688 self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?;
689 if has_changed == HasChanged::Yes {
690 unchanged_certainty = None;
691 }
692
693 match certainty {
694 Certainty::Yes => {}
695 Certainty::Maybe(_) => {
696 self.nested_goals.goals.push((source, goal));
697 unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
698 }
699 }
700 }
701
702 Ok(unchanged_certainty)
703 }
704
705 pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) {
707 self.inspect.record_impl_args(self.delegate, self.max_input_universe, impl_args)
708 }
709
710 pub(super) fn cx(&self) -> I {
711 self.delegate.cx()
712 }
713
714 #[instrument(level = "trace", skip(self))]
715 pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
716 goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(
717 self,
718 GoalSource::TypeRelating,
719 goal.param_env,
720 ));
721 self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
722 self.nested_goals.normalizes_to_goals.push(goal);
723 }
724
725 #[instrument(level = "debug", skip(self))]
726 pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
727 goal.predicate =
728 goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env));
729 self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
730 self.nested_goals.goals.push((source, goal));
731 }
732
733 #[instrument(level = "trace", skip(self, goals))]
734 pub(super) fn add_goals(
735 &mut self,
736 source: GoalSource,
737 goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
738 ) {
739 for goal in goals {
740 self.add_goal(source, goal);
741 }
742 }
743
744 pub(super) fn next_region_var(&mut self) -> I::Region {
745 let region = self.delegate.next_region_infer();
746 self.inspect.add_var_value(region);
747 region
748 }
749
750 pub(super) fn next_ty_infer(&mut self) -> I::Ty {
751 let ty = self.delegate.next_ty_infer();
752 self.inspect.add_var_value(ty);
753 ty
754 }
755
756 pub(super) fn next_const_infer(&mut self) -> I::Const {
757 let ct = self.delegate.next_const_infer();
758 self.inspect.add_var_value(ct);
759 ct
760 }
761
762 pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
765 match kind.kind() {
766 ty::TermKind::Ty(_) => self.next_ty_infer().into(),
767 ty::TermKind::Const(_) => self.next_const_infer().into(),
768 }
769 }
770
771 #[instrument(level = "trace", skip(self), ret)]
776 pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
777 let universe_of_term = match goal.predicate.term.kind() {
778 ty::TermKind::Ty(ty) => {
779 if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
780 self.delegate.universe_of_ty(vid).unwrap()
781 } else {
782 return false;
783 }
784 }
785 ty::TermKind::Const(ct) => {
786 if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
787 self.delegate.universe_of_ct(vid).unwrap()
788 } else {
789 return false;
790 }
791 }
792 };
793
794 struct ContainsTermOrNotNameable<'a, D: SolverDelegate<Interner = I>, I: Interner> {
795 term: I::Term,
796 universe_of_term: ty::UniverseIndex,
797 delegate: &'a D,
798 cache: HashSet<I::Ty>,
799 }
800
801 impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
802 fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
803 if self.universe_of_term.can_name(universe) {
804 ControlFlow::Continue(())
805 } else {
806 ControlFlow::Break(())
807 }
808 }
809 }
810
811 impl<D: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
812 for ContainsTermOrNotNameable<'_, D, I>
813 {
814 type Result = ControlFlow<()>;
815 fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
816 if self.cache.contains(&t) {
817 return ControlFlow::Continue(());
818 }
819
820 match t.kind() {
821 ty::Infer(ty::TyVar(vid)) => {
822 if let ty::TermKind::Ty(term) = self.term.kind() {
823 if let ty::Infer(ty::TyVar(term_vid)) = term.kind() {
824 if self.delegate.root_ty_var(vid)
825 == self.delegate.root_ty_var(term_vid)
826 {
827 return ControlFlow::Break(());
828 }
829 }
830 }
831
832 self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
833 }
834 ty::Placeholder(p) => self.check_nameable(p.universe())?,
835 _ => {
836 if t.has_non_region_infer() || t.has_placeholders() {
837 t.super_visit_with(self)?
838 }
839 }
840 }
841
842 assert!(self.cache.insert(t));
843 ControlFlow::Continue(())
844 }
845
846 fn visit_const(&mut self, c: I::Const) -> Self::Result {
847 match c.kind() {
848 ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
849 if let ty::TermKind::Const(term) = self.term.kind() {
850 if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
851 {
852 if self.delegate.root_const_var(vid)
853 == self.delegate.root_const_var(term_vid)
854 {
855 return ControlFlow::Break(());
856 }
857 }
858 }
859
860 self.check_nameable(self.delegate.universe_of_ct(vid).unwrap())
861 }
862 ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
863 _ => {
864 if c.has_non_region_infer() || c.has_placeholders() {
865 c.super_visit_with(self)
866 } else {
867 ControlFlow::Continue(())
868 }
869 }
870 }
871 }
872 }
873
874 let mut visitor = ContainsTermOrNotNameable {
875 delegate: self.delegate,
876 universe_of_term,
877 term: goal.predicate.term,
878 cache: Default::default(),
879 };
880 goal.predicate.alias.visit_with(&mut visitor).is_continue()
881 && goal.param_env.visit_with(&mut visitor).is_continue()
882 }
883
884 #[instrument(level = "trace", skip(self, param_env), ret)]
885 pub(super) fn eq<T: Relate<I>>(
886 &mut self,
887 param_env: I::ParamEnv,
888 lhs: T,
889 rhs: T,
890 ) -> Result<(), NoSolution> {
891 self.relate(param_env, lhs, ty::Variance::Invariant, rhs)
892 }
893
894 #[instrument(level = "trace", skip(self, param_env), ret)]
900 pub(super) fn relate_rigid_alias_non_alias(
901 &mut self,
902 param_env: I::ParamEnv,
903 alias: ty::AliasTerm<I>,
904 variance: ty::Variance,
905 term: I::Term,
906 ) -> Result<(), NoSolution> {
907 if term.is_infer() {
910 let cx = self.cx();
911 let identity_args = self.fresh_args_for_item(alias.def_id);
920 let rigid_ctor = ty::AliasTerm::new_from_args(cx, alias.def_id, identity_args);
921 let ctor_term = rigid_ctor.to_term(cx);
922 let obligations = self.delegate.eq_structurally_relating_aliases(
923 param_env,
924 term,
925 ctor_term,
926 self.origin_span,
927 )?;
928 debug_assert!(obligations.is_empty());
929 self.relate(param_env, alias, variance, rigid_ctor)
930 } else {
931 Err(NoSolution)
932 }
933 }
934
935 #[instrument(level = "trace", skip(self, param_env), ret)]
939 pub(super) fn eq_structurally_relating_aliases<T: Relate<I>>(
940 &mut self,
941 param_env: I::ParamEnv,
942 lhs: T,
943 rhs: T,
944 ) -> Result<(), NoSolution> {
945 let result = self.delegate.eq_structurally_relating_aliases(
946 param_env,
947 lhs,
948 rhs,
949 self.origin_span,
950 )?;
951 assert_eq!(result, vec![]);
952 Ok(())
953 }
954
955 #[instrument(level = "trace", skip(self, param_env), ret)]
956 pub(super) fn sub<T: Relate<I>>(
957 &mut self,
958 param_env: I::ParamEnv,
959 sub: T,
960 sup: T,
961 ) -> Result<(), NoSolution> {
962 self.relate(param_env, sub, ty::Variance::Covariant, sup)
963 }
964
965 #[instrument(level = "trace", skip(self, param_env), ret)]
966 pub(super) fn relate<T: Relate<I>>(
967 &mut self,
968 param_env: I::ParamEnv,
969 lhs: T,
970 variance: ty::Variance,
971 rhs: T,
972 ) -> Result<(), NoSolution> {
973 let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
974 for &goal in goals.iter() {
975 let source = match goal.predicate.kind().skip_binder() {
976 ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
977 GoalSource::TypeRelating
978 }
979 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc,
981 p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
982 };
983 self.add_goal(source, goal);
984 }
985 Ok(())
986 }
987
988 #[instrument(level = "trace", skip(self, param_env), ret)]
994 pub(super) fn eq_and_get_goals<T: Relate<I>>(
995 &self,
996 param_env: I::ParamEnv,
997 lhs: T,
998 rhs: T,
999 ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
1000 Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
1001 }
1002
1003 pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
1004 &self,
1005 value: ty::Binder<I, T>,
1006 ) -> T {
1007 self.delegate.instantiate_binder_with_infer(value)
1008 }
1009
1010 pub(super) fn enter_forall<T: TypeFoldable<I>, U>(
1013 &mut self,
1014 value: ty::Binder<I, T>,
1015 f: impl FnOnce(&mut Self, T) -> U,
1016 ) -> U {
1017 self.delegate.enter_forall(value, |value| f(self, value))
1018 }
1019
1020 pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
1021 where
1022 T: TypeFoldable<I>,
1023 {
1024 self.delegate.resolve_vars_if_possible(value)
1025 }
1026
1027 pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
1028 let args = self.delegate.fresh_args_for_item(def_id);
1029 for arg in args.iter() {
1030 self.inspect.add_var_value(arg);
1031 }
1032 args
1033 }
1034
1035 pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
1036 self.delegate.register_ty_outlives(ty, lt, self.origin_span);
1037 }
1038
1039 pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
1040 self.delegate.sub_regions(b, a, self.origin_span);
1042 }
1043
1044 pub(super) fn well_formed_goals(
1046 &self,
1047 param_env: I::ParamEnv,
1048 arg: I::GenericArg,
1049 ) -> Option<Vec<Goal<I, I::Predicate>>> {
1050 self.delegate.well_formed_goals(param_env, arg)
1051 }
1052
1053 pub(super) fn trait_ref_is_knowable(
1054 &mut self,
1055 param_env: I::ParamEnv,
1056 trait_ref: ty::TraitRef<I>,
1057 ) -> Result<bool, NoSolution> {
1058 let delegate = self.delegate;
1059 let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
1060 coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty)
1061 .map(|is_knowable| is_knowable.is_ok())
1062 }
1063
1064 pub(super) fn fetch_eligible_assoc_item(
1065 &self,
1066 goal_trait_ref: ty::TraitRef<I>,
1067 trait_assoc_def_id: I::DefId,
1068 impl_def_id: I::DefId,
1069 ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
1070 self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
1071 }
1072
1073 pub(super) fn insert_hidden_type(
1074 &mut self,
1075 opaque_type_key: ty::OpaqueTypeKey<I>,
1076 param_env: I::ParamEnv,
1077 hidden_ty: I::Ty,
1078 ) -> Result<(), NoSolution> {
1079 let mut goals = Vec::new();
1080 self.delegate.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?;
1081 self.add_goals(GoalSource::Misc, goals);
1082 Ok(())
1083 }
1084
1085 pub(super) fn add_item_bounds_for_hidden_type(
1086 &mut self,
1087 opaque_def_id: I::DefId,
1088 opaque_args: I::GenericArgs,
1089 param_env: I::ParamEnv,
1090 hidden_ty: I::Ty,
1091 ) {
1092 let mut goals = Vec::new();
1093 self.delegate.add_item_bounds_for_hidden_type(
1094 opaque_def_id,
1095 opaque_args,
1096 param_env,
1097 hidden_ty,
1098 &mut goals,
1099 );
1100 self.add_goals(GoalSource::AliasWellFormed, goals);
1101 }
1102
1103 pub(super) fn probe_existing_opaque_ty(
1106 &mut self,
1107 key: ty::OpaqueTypeKey<I>,
1108 ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1109 let mut matching =
1110 self.delegate.clone_opaque_types_for_query_response().into_iter().filter(
1111 |(candidate_key, _)| {
1112 candidate_key.def_id == key.def_id
1113 && DeepRejectCtxt::relate_rigid_rigid(self.cx())
1114 .args_may_unify(candidate_key.args, key.args)
1115 },
1116 );
1117 let first = matching.next();
1118 let second = matching.next();
1119 assert_eq!(second, None);
1120 first
1121 }
1122
1123 pub(super) fn evaluate_const(
1127 &self,
1128 param_env: I::ParamEnv,
1129 uv: ty::UnevaluatedConst<I>,
1130 ) -> Option<I::Const> {
1131 self.delegate.evaluate_const(param_env, uv)
1132 }
1133
1134 pub(super) fn is_transmutable(
1135 &mut self,
1136 dst: I::Ty,
1137 src: I::Ty,
1138 assume: I::Const,
1139 ) -> Result<Certainty, NoSolution> {
1140 self.delegate.is_transmutable(dst, src, assume)
1141 }
1142}
1143
1144struct ReplaceAliasWithInfer<'me, 'a, D, I>
1159where
1160 D: SolverDelegate<Interner = I>,
1161 I: Interner,
1162{
1163 ecx: &'me mut EvalCtxt<'a, D>,
1164 param_env: I::ParamEnv,
1165 normalization_goal_source: GoalSource,
1166 cache: HashMap<I::Ty, I::Ty>,
1167}
1168
1169impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1170where
1171 D: SolverDelegate<Interner = I>,
1172 I: Interner,
1173{
1174 fn new(
1175 ecx: &'me mut EvalCtxt<'a, D>,
1176 for_goal_source: GoalSource,
1177 param_env: I::ParamEnv,
1178 ) -> Self {
1179 let step_kind = ecx.step_kind_for_source(for_goal_source);
1180 ReplaceAliasWithInfer {
1181 ecx,
1182 param_env,
1183 normalization_goal_source: GoalSource::NormalizeGoal(step_kind),
1184 cache: Default::default(),
1185 }
1186 }
1187}
1188
1189impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
1190where
1191 D: SolverDelegate<Interner = I>,
1192 I: Interner,
1193{
1194 fn cx(&self) -> I {
1195 self.ecx.cx()
1196 }
1197
1198 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1199 match ty.kind() {
1200 ty::Alias(..) if !ty.has_escaping_bound_vars() => {
1201 let infer_ty = self.ecx.next_ty_infer();
1202 let normalizes_to = ty::PredicateKind::AliasRelate(
1203 ty.into(),
1204 infer_ty.into(),
1205 ty::AliasRelationDirection::Equate,
1206 );
1207 self.ecx.add_goal(
1208 self.normalization_goal_source,
1209 Goal::new(self.cx(), self.param_env, normalizes_to),
1210 );
1211 infer_ty
1212 }
1213 _ => {
1214 if !ty.has_aliases() {
1215 ty
1216 } else if let Some(&entry) = self.cache.get(&ty) {
1217 return entry;
1218 } else {
1219 let res = ty.super_fold_with(self);
1220 assert!(self.cache.insert(ty, res).is_none());
1221 res
1222 }
1223 }
1224 }
1225 }
1226
1227 fn fold_const(&mut self, ct: I::Const) -> I::Const {
1228 match ct.kind() {
1229 ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
1230 let infer_ct = self.ecx.next_const_infer();
1231 let normalizes_to = ty::PredicateKind::AliasRelate(
1232 ct.into(),
1233 infer_ct.into(),
1234 ty::AliasRelationDirection::Equate,
1235 );
1236 self.ecx.add_goal(
1237 self.normalization_goal_source,
1238 Goal::new(self.cx(), self.param_env, normalizes_to),
1239 );
1240 infer_ct
1241 }
1242 _ => ct.super_fold_with(self),
1243 }
1244 }
1245
1246 fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
1247 if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
1248 }
1249}