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 if cfg!(debug_assertions) {
975 for g in goals.iter() {
976 match g.predicate.kind().skip_binder() {
977 ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {}
978 p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
979 }
980 }
981 }
982 self.add_goals(GoalSource::TypeRelating, goals);
983 Ok(())
984 }
985
986 #[instrument(level = "trace", skip(self, param_env), ret)]
992 pub(super) fn eq_and_get_goals<T: Relate<I>>(
993 &self,
994 param_env: I::ParamEnv,
995 lhs: T,
996 rhs: T,
997 ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
998 Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
999 }
1000
1001 pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
1002 &self,
1003 value: ty::Binder<I, T>,
1004 ) -> T {
1005 self.delegate.instantiate_binder_with_infer(value)
1006 }
1007
1008 pub(super) fn enter_forall<T: TypeFoldable<I>, U>(
1011 &mut self,
1012 value: ty::Binder<I, T>,
1013 f: impl FnOnce(&mut Self, T) -> U,
1014 ) -> U {
1015 self.delegate.enter_forall(value, |value| f(self, value))
1016 }
1017
1018 pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
1019 where
1020 T: TypeFoldable<I>,
1021 {
1022 self.delegate.resolve_vars_if_possible(value)
1023 }
1024
1025 pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
1026 let args = self.delegate.fresh_args_for_item(def_id);
1027 for arg in args.iter() {
1028 self.inspect.add_var_value(arg);
1029 }
1030 args
1031 }
1032
1033 pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
1034 self.delegate.register_ty_outlives(ty, lt, self.origin_span);
1035 }
1036
1037 pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
1038 self.delegate.sub_regions(b, a, self.origin_span);
1040 }
1041
1042 pub(super) fn well_formed_goals(
1044 &self,
1045 param_env: I::ParamEnv,
1046 arg: I::GenericArg,
1047 ) -> Option<Vec<Goal<I, I::Predicate>>> {
1048 self.delegate.well_formed_goals(param_env, arg)
1049 }
1050
1051 pub(super) fn trait_ref_is_knowable(
1052 &mut self,
1053 param_env: I::ParamEnv,
1054 trait_ref: ty::TraitRef<I>,
1055 ) -> Result<bool, NoSolution> {
1056 let delegate = self.delegate;
1057 let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
1058 coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty)
1059 .map(|is_knowable| is_knowable.is_ok())
1060 }
1061
1062 pub(super) fn fetch_eligible_assoc_item(
1063 &self,
1064 goal_trait_ref: ty::TraitRef<I>,
1065 trait_assoc_def_id: I::DefId,
1066 impl_def_id: I::DefId,
1067 ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
1068 self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
1069 }
1070
1071 pub(super) fn insert_hidden_type(
1072 &mut self,
1073 opaque_type_key: ty::OpaqueTypeKey<I>,
1074 param_env: I::ParamEnv,
1075 hidden_ty: I::Ty,
1076 ) -> Result<(), NoSolution> {
1077 let mut goals = Vec::new();
1078 self.delegate.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?;
1079 self.add_goals(GoalSource::Misc, goals);
1080 Ok(())
1081 }
1082
1083 pub(super) fn add_item_bounds_for_hidden_type(
1084 &mut self,
1085 opaque_def_id: I::DefId,
1086 opaque_args: I::GenericArgs,
1087 param_env: I::ParamEnv,
1088 hidden_ty: I::Ty,
1089 ) {
1090 let mut goals = Vec::new();
1091 self.delegate.add_item_bounds_for_hidden_type(
1092 opaque_def_id,
1093 opaque_args,
1094 param_env,
1095 hidden_ty,
1096 &mut goals,
1097 );
1098 self.add_goals(GoalSource::AliasWellFormed, goals);
1099 }
1100
1101 pub(super) fn probe_existing_opaque_ty(
1104 &mut self,
1105 key: ty::OpaqueTypeKey<I>,
1106 ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1107 let mut matching =
1108 self.delegate.clone_opaque_types_for_query_response().into_iter().filter(
1109 |(candidate_key, _)| {
1110 candidate_key.def_id == key.def_id
1111 && DeepRejectCtxt::relate_rigid_rigid(self.cx())
1112 .args_may_unify(candidate_key.args, key.args)
1113 },
1114 );
1115 let first = matching.next();
1116 let second = matching.next();
1117 assert_eq!(second, None);
1118 first
1119 }
1120
1121 pub(super) fn evaluate_const(
1125 &self,
1126 param_env: I::ParamEnv,
1127 uv: ty::UnevaluatedConst<I>,
1128 ) -> Option<I::Const> {
1129 self.delegate.evaluate_const(param_env, uv)
1130 }
1131
1132 pub(super) fn is_transmutable(
1133 &mut self,
1134 dst: I::Ty,
1135 src: I::Ty,
1136 assume: I::Const,
1137 ) -> Result<Certainty, NoSolution> {
1138 self.delegate.is_transmutable(dst, src, assume)
1139 }
1140}
1141
1142struct ReplaceAliasWithInfer<'me, 'a, D, I>
1157where
1158 D: SolverDelegate<Interner = I>,
1159 I: Interner,
1160{
1161 ecx: &'me mut EvalCtxt<'a, D>,
1162 param_env: I::ParamEnv,
1163 normalization_goal_source: GoalSource,
1164 cache: HashMap<I::Ty, I::Ty>,
1165}
1166
1167impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1168where
1169 D: SolverDelegate<Interner = I>,
1170 I: Interner,
1171{
1172 fn new(
1173 ecx: &'me mut EvalCtxt<'a, D>,
1174 for_goal_source: GoalSource,
1175 param_env: I::ParamEnv,
1176 ) -> Self {
1177 let step_kind = ecx.step_kind_for_source(for_goal_source);
1178 ReplaceAliasWithInfer {
1179 ecx,
1180 param_env,
1181 normalization_goal_source: GoalSource::NormalizeGoal(step_kind),
1182 cache: Default::default(),
1183 }
1184 }
1185}
1186
1187impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
1188where
1189 D: SolverDelegate<Interner = I>,
1190 I: Interner,
1191{
1192 fn cx(&self) -> I {
1193 self.ecx.cx()
1194 }
1195
1196 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1197 match ty.kind() {
1198 ty::Alias(..) if !ty.has_escaping_bound_vars() => {
1199 let infer_ty = self.ecx.next_ty_infer();
1200 let normalizes_to = ty::PredicateKind::AliasRelate(
1201 ty.into(),
1202 infer_ty.into(),
1203 ty::AliasRelationDirection::Equate,
1204 );
1205 self.ecx.add_goal(
1206 self.normalization_goal_source,
1207 Goal::new(self.cx(), self.param_env, normalizes_to),
1208 );
1209 infer_ty
1210 }
1211 _ => {
1212 if !ty.has_aliases() {
1213 ty
1214 } else if let Some(&entry) = self.cache.get(&ty) {
1215 return entry;
1216 } else {
1217 let res = ty.super_fold_with(self);
1218 assert!(self.cache.insert(ty, res).is_none());
1219 res
1220 }
1221 }
1222 }
1223 }
1224
1225 fn fold_const(&mut self, ct: I::Const) -> I::Const {
1226 match ct.kind() {
1227 ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
1228 let infer_ct = self.ecx.next_const_infer();
1229 let normalizes_to = ty::PredicateKind::AliasRelate(
1230 ct.into(),
1231 infer_ct.into(),
1232 ty::AliasRelationDirection::Equate,
1233 );
1234 self.ecx.add_goal(
1235 self.normalization_goal_source,
1236 Goal::new(self.cx(), self.param_env, normalizes_to),
1237 );
1238 infer_ct
1239 }
1240 _ => ct.super_fold_with(self),
1241 }
1242 }
1243
1244 fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
1245 if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
1246 }
1247}